文章目录
CountDownLatch(做减法)
定义:线程同步工具类,允许一个或多个线程一直等待,直到其他线程执行完再被唤醒。在多线程环境下,它指定一个计数器的初始值target,然后可被多个线程并发的实现减 1 操作,并在计数器为 0 后调用 await 方法的线程被唤醒,从而实现多线程间的协作。
应用场景:CountDownLatch非常适合于对任务进行拆分,使其并行执行,比如某个任务执行2s,其对数据的请求可以分为五个部分,那么就可以将这个任务拆分为5个子任务,分别交由五个线程执行,执行完成之后再由主线程进行汇总,此时,总的执行时间将决定于执行最慢的任务,平均来看,还是大大减少了总的执行时间。
主要方法:
CountDownLatch countDownLatch = new CountDownLatch(6);
countDownLatch.countDown(); //计数器减1
countDownLatch.await(); //调用线程会被阻塞,当计数器为0时,才会被唤醒
static CountDownLatch c = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
c.countDown(); // -1
System.out.println(2);
c.countDown(); // -1
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(3);
c.countDown(); // -1
}
}).start();
c.await(); // 一直等到计算器为0
System.out.println("over");
}
CyclicBarrier(做加法)
定义:字面意思是可循环使用的屏障,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门。初始值0,计数器target再执行(做加法)
应用场景:当主线程进行执行时,利用构造方法初始化一个屏障数和剩余屏障数,子线程调用await方法进行阻塞自身,待到当前组剩余屏障数为0时则唤醒当前组所有被阻塞的线程,然后再执行子线程中的剩余逻辑。
主要方法:
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 0; i < 10; i++){
int num = i;
new Thread(()->{
System.out.println("线程"+num+"初始化!");
try {
cyclicBarrier.await(); //先来的线程,被阻塞
System.out.println("------------------线程"+num+"被唤醒执行!-----------------");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
System.out.println("main 线程执行!");
}
Semaphore
定义:多个线程争抢多个共享资源。主要用于两个目的,一是用于多个共享资源的互斥使用,另一个是用于控制并发线程数目(争车位)
应用场景:Semaphore的基本使用场景是限制一定数量的线程能够去执行.
举个简单的例子: 一个单向隧道能同时容纳10个小汽车或5个卡车通过(1个卡车等效与2个小汽车), 而隧道入口记录着当前已经在隧道内的汽车等效比重. 比如1个小汽车和1个卡车, 则隧道入口显示3. 若隧道入口显示10表示已经满了. 当汽车驶出隧道之后, 隧道入口显示的数字则会相应的减小. 于这个示例相符合场景非常适合用信号量.
常用方法:
public static void main(String[] args) {
Semaphore sem = new Semaphore(2);//共享资源是2个许可
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
sem.acquire();// 默认使用一个许可.
System.out.println(Thread.currentThread() + " I get it.");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread() + " I release it.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
sem.release();//释放资源
}
}).start();
}
}
CompletableFuture
定义:CompletableFuture是jdk8的新特性。CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步会点、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利。
创建异步任务
/**
* 一、创建异步任务.
* 带返回值异步请求,默认线程池: public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
* 带返回值的异步请求,自定义线程池: public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
* 不带返回值的异步请求,默认线程池 : public static CompletableFuture<Void> runAsync(Runnable runnable)
* 不带返回值的异步请求,自定义线程池: public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
* 二、获取任务结果的方法
* public T get() 如果完成则返回结果,否则就抛出具体的异常
* public T get(long timeout, TimeUnit unit) 最大时间等待返回结果,否则就抛出具体异常
* public T getNow(T valueIfAbsent) 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent
* public boolean complete(T value) 如果任务没有完成,返回的值设置为给定值
* public boolean completeExceptionally(Throwable ex) 如果任务没有完成,就抛出给定异常
* public T join() 完成时返回结果值,否则抛出unchecked异常
*/
public static void test001() throws Exception {
// 1、带返回值异步请求,默认线程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("1-带返回值异步请求,默认线程池 is running...");
return "supplyAsync001";
});
// 2、带返回值的异步请求,自定义线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("2-带返回值异步请求,自定义线程池 is running...");
return "supplyAsync002";
}, threadPool);
// 3、不带返回值的异步请求,默认线程池
CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
System.out.println("3-不带返回值的异步请求,默认线程池 is running...");
});
// 4、不带返回值的异步请求,自定义线程池
CompletableFuture<Void> future4 = CompletableFuture.runAsync(() -> {
System.out.println("4-不带返回值的异步请求,自定义线程池 is running...");
});
// 5、获取任务结果的方法
System.out.println("future1.isDone() = " + future1.isDone());
System.out.println("future1.get() = " + future1.get()); // 若任务没有完成,会阻塞一直等待到任务完成获得结果,后续代码继续执行
System.out.println("future1.join() = " + future1.join()); // 若任务没有完成,会阻塞一直等待到任务完成获得结果,后续代码继续执行
System.out.println("future1.getNow(\"default\") = " + future1.getNow("default")); // 若任务没有完成,则返回给定的 valueIfAbsent
System.out.println("future1.complete(\"supplyAsync001\") = " + future1.complete("supplyAsync001111"));
System.out.println("future1.get(1, TimeUnit.SECONDS) = " + future1.get(1, TimeUnit.SECONDS)); // 若任务没有完成,则会抛异常,后续逻辑代码不会执行了:java.util.concurrent.TimeoutException
}
异步回调处理
/**
* 三、异步回调处理
* <p>
* 1、thenApply和thenApplyAsync: 表示某个任务执行完成后执行的动作,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值【有入参、有返回值】
* 2、thenAccept和thenAcceptAsync:表示某个任务执行完成后执行的动作,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,无返回值【有入参、无返回值】
* 3、thenRun和thenRunAsync: 表示某个任务执行完成后执行的动作【无入参,无返回值】
* 4、whenComplete和whenCompleteAsync:当某个任务执行完成后执行的回调方法,会将执行结果或者执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。
* 5、handle和handleAsync:跟whenComplete基本一致,区别在于handle的回调方法有返回值。
*/
public static void test002() throws Exception {
// 1、thenApply和thenApplyAsync:有入参、有返回值
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("future1 do something....");
return 100;
}).thenApplyAsync(result -> {
// 将result = 100 作为入参,执行回调方法
System.out.println("thenApplyAsync do something....");
return result + 200;
});
System.out.println("future1.get() = " + future1.get());
// 2、thenAccept和thenAcceptAsync:有入参、无返回值
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("future2 do something....");
return 100;
}).thenAcceptAsync(result -> {
// 将result = 100 作为入参,执行回调方法
System.out.println("thenAcceptAsync do something....");
System.out.println("result * 3 = " + result * 3);
});
System.out.println("future2.get() = " + future2.get());
// 3、thenRun和thenRunAsync:无入参、无返回值
CompletableFuture<Void> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("future3 do something....");
return 100;
}).thenRunAsync(() -> {
System.out.println("thenRunAsync");
});
System.out.println("future3.get() = " + future3.get());
// 4、whenComplete和whenCompleteAsync:有入参、无返回值
CompletableFuture<Integer> future4 = CompletableFuture.supplyAsync(() -> {
System.out.println("future4 do something....");
return 100;
}).whenCompleteAsync((result, ex) -> {
System.out.println("result = " + result);
System.out.println("ex = " + ex);
});
System.out.println("future4.get() = " + future4.get());
// 5、handle和handleAsync:有入参、有返回值
CompletableFuture<Integer> future5 = CompletableFuture.supplyAsync(() -> {
System.out.println("future5 do something....");
return 1;
}).handle((result, e) -> {
System.out.println("handle do something....");
System.out.println("上个任务结果:" + result);
System.out.println("上个任务抛出异常:" + e);
return result + 2;
});
System.out.println("future5.get() = " + future5.get());
}
多任务组合处理之一
/**
* 四、多任务组合处理之一
* allOf:CompletableFuture是多个任务都执行完成后才会执行,只有有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。
* anyOf :CompletableFuture是多个任务只要有一个任务执行完成,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回执行完成任务的结果。
*/
public static void test003() throws Exception {
// 1、自定义三个任务
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf1任务完成");
return "cf1任务完成";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf2任务完成");
return "cf2任务完成";
});
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cf3任务完成");
return "cf3任务完成";
});
// 2、allOf 所有任务都执行完成,才执行thenApply【todo 肯定获取结果后还可以做点业务逻辑】
CompletableFuture<Void> allOfRes = CompletableFuture.allOf(future1, future2, future3);
System.out.println("allOfRes.get() = " + allOfRes.get());
// 3、anyOf 任意一个任务完成,就执行thenApply
CompletableFuture<Object> anyOfRes = CompletableFuture.anyOf(future1, future2, future3);
System.out.println("anyOfRes.get() = " + anyOfRes.get());
}
多任务组合处理之二
/**
* 四、多任务组合处理之二
* thenCombine、thenAcceptBoth 和runAfterBoth:
* 相同点: 这三个方法都是将两个CompletableFuture组合起来处理,只有两个任务都正常完成时,才进行下阶段任务。
* 区别:
* thenCombine:将两个任务的执行结果作为所提供函数的参数,且该方法有返回值【有入参、有返回值】;
* thenAcceptBoth:将两个任务的执行结果作为方法入参,但是无返回值;【有入参、无返回值】
* runAfterBoth:两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。【无入参、无返回值】
*/
public static void test004() throws Exception {
// 自定义两个任务
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf1 do something....");
return 1;
});
CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + " cf2 do something....");
return 2;
});
// thenCombine:有入参、有返回值
CompletableFuture<Integer> cf3 = cf1.thenCombine(cf2, (a, b) -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
return a + b;
});
System.out.println("cf3结果->" + cf3.get());
// thenAcceptBoth:有入参、无返回值
CompletableFuture<Void> cf4 = cf1.thenAcceptBoth(cf2, (a, b) -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
System.out.println(a + b);
});
System.out.println("cf4.get() = " + cf4.get());
// runAfterBoth:无入参、无返回值
CompletableFuture<Void> cf5 = cf1.runAfterBoth(cf2, () -> {
System.out.println(Thread.currentThread() + " cf3 do something....");
});
System.out.println("cf5.get() = " + cf5.get());
}
多任务组合处理之三
/**
* 四、多任务组合处理之三
* applyToEither、acceptEither和runAfterEither
* 相同点:这三个方法和上面一样也是将两个CompletableFuture组合起来处理,当有一个任务正常完成时,就会进行下阶段任务。
* 区别:
* applyToEither会将已经完成任务的执行结果作为所提供函数的参数,且该方法有返回值;【有入参、有返回值】;
* acceptEither同样将已经完成任务的执行结果作为方法入参,但是无返回值;【有入参、无返回值】
* runAfterEither没有入参,也没有返回值。【无入参、无返回值】
*/
public static void test005() throws Exception {
// 自定义两个任务
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf1 do something....");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf1 任务完成";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
System.out.println(Thread.currentThread() + " cf2 do something....");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "cf2 任务完成";
});
// applyToEither:有入参、有返回值
CompletableFuture<String> cf3 = cf1.applyToEither(cf2, (result) -> {
System.out.println("接收到" + result);
System.out.println(Thread.currentThread() + " cf3 do something....");
return "cf3 任务完成";
});
System.out.println("cf3结果->" + cf3.get());
// acceptEither:有入参、无返回值
CompletableFuture<Void> cf4 = cf1.acceptEither(cf2, (result) -> {
System.out.println("接收到" + result);
System.out.println(Thread.currentThread() + " cf4 do something....");
});
System.out.println("cf4结果->" + cf4.get());
// runAfterEither:无入参、无返回值
CompletableFuture<Void> cf5 = cf1.runAfterEither(cf2, () -> {
System.out.println(Thread.currentThread() + " cf5 do something....");
System.out.println("cf5 任务完成");
});
System.out.println("cf5结果->" + cf3.get());
}