1.实现线程的几种方式
-
继承Thread
public static class Thread01 extends Thread{ @Override public void run() { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("当前运行结果:" + i); } }
-
继承Runable
public static class Runnable01 implements Runnable{ @Override public void run() { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("当前运行结果:" + i); } }
-
实现Callable接口
public static class Callable01 implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("当前线程:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("当前运行结果:" + i); return i; } }
-
实现Callable接口+FutureTask
可以得到返回值
public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main.............start......."); // 1、继承Thread Thread01 thread01 = new Thread01(); thread01.start();//启动线程 // 2、实现Runnable Runnable01 runnable01 = new Runnable01(); new Thread(runnable01).start(); // 3、实现Callable接口+FutureTask FutureTask<Integer> futureTask = new FutureTask<>(new Callable01()); new Thread(futureTask).start(); //阻塞等待整个线程执行完成,获取返回结果 Integer integer = futureTask.get(); // 4、线程池 service.execute(new Runnable01()); System.out.println("main.............end......."+integer); }
-
线程池
也可以得到返回值,具体应用在下面介绍。
2.线程池
-
参数解释
corePoolSize,核心线程数[一直存在,除非(allowCoreThreadTimeOut)];线程池,创建好以后就准备就绪的线程数量,就等待接收异步任务去执行 maximumPoolSize:最大线程数量;控制资源 keepAliveTime:存活时间。 unit:时间单位 BlockingQueue<Runnable> workQueue:阻塞队列。如果任务有很多。就会将多的任务放在队列里面,只要有线程空闲,就会去队列里面取出新的任务继续执行 ThreadFactory:线程创建的工厂 RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略,拒绝执行
-
执行顺序
- 创建线程池并初始化,准备被调用
- 如果core线程全都在调用中,将新的任务放在阻塞队列中。core线程执行完,就会去阻塞队列中获取新的任务
- 如果阻塞队列满了,那么就会创建新的线程执行任务,但是最大线程数量只能到maximumPoolSize
- max也满了,就会使用拒绝策略
- 如果max空闲了,存活时间达到keepAliveTime就会被自动释放
-
配置形式
@EnableConfigurationProperties(ThreadPoolConfigProperties.class) @Configuration public class MyThreadConfig { @Bean public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) { return new ThreadPoolExecutor( pool.getCoreSize(), pool.getMaxSize(), pool.getKeepAliveTime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); } }
-
常见的4中线程池
newCachedThreadPool:创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
-
使用线程池的优点
降低资源的消耗:通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
提高响应速度:因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
提高线程的可管理性:线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配
3.CompletableFuture组合式异步编程
-
异步方法的创建
CompletableFuture中有 runAsync 和 supplyAsync方法
public static CompletableFuture<Void> runAsync(Runnable runnable) //可以指定线程池 public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) //可以指定线程池 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
在 runAsync 和 supplyAsync方法都可以指定线程池,但是runAsync方法不支持返回值,supplyAsync方法支持返回值。
public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main.............start......."); //runAsync方法 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 2; System.out.println("当前运行结果:" + i); }, executor); //supplyAsync方法 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 2; System.out.println("当前运行结果:" + i); return i; }, executor); Integer integer = future.get(); System.out.println("main.............end......."+integer); }
-
异步方法完成后调用方法
提供以下的几种方法:
//可以处理异常,无返回值 public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor) //可以处理异常,有返回值 public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
使用:
public class ThreadTest { public static ExecutorService executor = Executors.newFixedThreadPool(10); public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main.............start......."); CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 0; System.out.println("当前运行结果:" + i); return i; }, executor).whenComplete((result,exception)->{ //虽然能得到异常信息,但是没法修改返回数据 System.out.println("异步任务完成了...结果是"+result+";异常是"+exception); //可以感知异常,同时返回默认值 }).exceptionally(throwable -> { return 10; }); Integer integer = future.get(); System.out.println("main.............end......."+integer); }
-
handle方法
handle 是执行任务完成时对结果的处理。handle 是在任务完成后再执行,还可以处理异常的任务。
提供以下几种方法
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn); public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn); public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Execut
实现:
public class ThreadTest { public static ExecutorService executor = Executors.newFixedThreadPool(10); public static void main(String[] args) throws ExecutionException, InterruptedException { /** * 方法执行完成后的处理 */ CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 5; System.out.println("当前运行结果:" + i); return i; }, executor).handle((result,exception)->{ if (result != null){ return result*2; } if (exception != null){ return 0; } return 0; }); Integer integer = future.get(); System.out.println("main.............end......."+integer); }
-
线程串行话
提供以下几种方法:
public <U>CompletableFuture<U>thenApply(Function<?super T,? extends U>fn) public <U>CompletableFuture<U>thenApplyAsync(Function<?super T,? extends U>fn) public <U>CompletableFuture<U>thenApplyAsync(Function<?super T,? extends U>fn, Executor executor) public Completionstage<void>thenAccept(Consumer<?super T>action); public CompletionStage<void>thenAcceptAsync(Consumer<?super T>action); public CompletionStage<void>thenAcceptAsync(Consumer<?super T>action,Executor executor); public Completionstage<void>thenRun(Runnable action); public CompletionStage<void>thenRunAsync(Runnable action); public Completionstage<void>thenRunAsync(Runnable action,Executor executor),
- **thenRun:**不能获取上一步的执行结果
- **thenAcceptAsync:**能接受上一步结果,但是无返回值
- **thenApplyAsync:**能接受上一步结果,有返回值
实现:
public class ThreadTest { public static ExecutorService executor = Executors.newFixedThreadPool(10); public static void main(String[] args) throws ExecutionException, InterruptedException { /** * 线程串行化 * 1)、thenRun 不能获取得到上一步的执行结果 */ CompletableFuture<Void> thenRunAsync = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 5; System.out.println("当前运行结果:" + i); return i; }, executor).thenRunAsync(() -> { System.out.println("任务2启动了。。。。"); }, executor); /** * 线程串行化 * 1)、thenRun 不能获取得到上一步的执行结果,无返回值 * 2)、thenAcceptAsync能接收上一步返回结果,但无返回值 */ CompletableFuture<Void> thenRunAsync = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 5; System.out.println("当前运行结果:" + i); return i; }, executor).thenAcceptAsync(res -> { System.out.println("任务2启动了。。。。"+res); }, executor); /** * 线程串行化 * 1)、thenRun 不能获取得到上一步的执行结果,无返回值 * 2)、thenAcceptAsync能接收上一步返回结果,但无返回值 * 3)、thenApplyAsync能接收上一步的返回结果,也有返回值 */ CompletableFuture<String> thenApplyAsync = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId()); int i = 10 / 5; System.out.println("当前运行结果:" + i); return i; }, executor).thenApplyAsync(res -> { System.out.println("任务2启动了。。。。" + res); return "hello" + res; }, executor); System.out.println("main.............end......."+ thenApplyAsync.get()); }
-
组合-两个任务都需完成
-
runAfterBoth:两个CompletionStage,都完成了计算才会执行下一步的操作
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor
-
thenAcceptBoth:当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行处理
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
-
thenCombine:thenCombine 会把两个CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 处理。
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
实现:
/** * 不能得到两个任务的参数,也无返回结果 */ future01.runAfterBothAsync(future02,()->{ System.out.println("任务三开始。。。"); },executor); /** * 能得到两个任务的参数,无返回结果 */ future01.thenAcceptBothAsync(future02,(f1,f2)->{ System.out.println("任务三开始。。。之前的结果"+f1+":"+f2); },executor); /** * 能得到两个任务的参数,无返回结果 */ CompletableFuture<String> thenCombineAsync = future01.thenCombineAsync(future02, (f1, f2) -> { System.out.println("任务三开始。。。之前的结果" + f1 + ":" + f2); return f1 + ":" + f2 + "->haha"; }, executor); System.out.println("main.............end......." + thenCombineAsync.get()); }
-
-
组合-两个任务只需要其中一个完成
-
runAfterEither:两个CompletionStage,任何一个完成了都会执行下一步的操作
public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
-
acceptEither:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行处理
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? supe
-
applyToEither:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn); public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn); public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? sup
-
thenCompose:允许对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn); public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) ; public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage
-
-
多任务组合
-
allOf:等待所有任务完成后进行下一步
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> { System.out.println("查询商品的属性"); return "黑色+256g"; },executor); CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(3000); System.out.println("查询商品的图片信息"); } catch (InterruptedException e) { e.printStackTrace(); } return "hello.jpg"; },executor); CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> { System.out.println("查询商品的介绍"); return "华为"; },executor); CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc); allOf.get();//等待所有线程执行完 System.out.println("main.............end......."+futureAttr.get()+"=>"+futureImg.get()+"=>"+futureDesc.get() ); }
-
anyOf:只要其中有一个任务完成即可执行下一步
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> { System.out.println("查询商品的属性"); return "黑色+256g"; },executor); CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(3000); System.out.println("查询商品的图片信息"); } catch (InterruptedException e) { e.printStackTrace(); } return "hello.jpg"; },executor); CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> { System.out.println("查询商品的介绍"); return "华为"; },executor); // CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc); // allOf.get();//等待所有线程执行完 CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureAttr, futureImg, futureDesc); System.out.println("main.............end......."+anyOf.get() );
-
总结
本篇我们介绍了有关异步的常用知识,包括线程的创建、线程池、CompletableFuture的使用,在项目中需要根据具体情况决定如何使用。