异步方法是什么?
每次启动程序时,系统会⾃动在内存中创建⼀个进程。进程是构成运⾏程序的资源的集合。这些资源包括虚地址空间、⽂件句柄和许多其他程序运 ⾏所需的资源。 在进程的内部,系统会创建⼀个称为线程的内核(Kerne)的对象,它代表了真正的运⾏程序。线程是执⾏线程的简称。当进程建⽴,系统就会 由主程序的Main⽅法的第⼀⾏语句处开始了线程的执⾏。
在默认情况下,⼀个进程只包含⼀个线程,即从程序的开始,⼀直执⾏到结束。
其实线程是可以派⽣其他线程,在任意时刻,⼀个进程都可以包含不同状态的多个线程,来执⾏程序的不同部分。
如果⼀个进程拥有⼀个线程,它们将共享进程的资源。 系统为处理器规划的执⾏单元,是线程⽽⾮进程。
在很多时候,我们在进程中使⽤单⼀线程从头到尾地执⾏程序,这种简单模式会导致性能和⽤户体验另⼈难以接受。
⽐如程序向另外⼀台服务器发出请求,由于⽹络等外部原因,此种通信任务往往会耗费⼤量时间,进程如果在此期间仅仅只能等待⽹络或⽹络上其他机器的响应,将严重地降低了性能。程序不应该浪费等待的时间,⽽应该更加⾼效地利⽤,在等待的时间执⾏其他任务,回复到达后在继续执⾏ 第⼀个任务。 如果程序调⽤某个⽅法,等待其执⾏全部处理后才能继续执⾏,我们称其为同步的。相反,在处理完成之前就返回调⽤⽅法则是异步的。
我们在编程语⾔的流程中添加了异步控制的部分,这部分的编程可以称之为异步编程。
简而言之:异步编程相对于单体线程而言,不像单体编程那样等上面的代码执行完才能执行下面的 ,他是可以同时多部分一起进行运行的,在代码运行过程能大大节省时间提升效率;
关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间;异步编程跟同步编程模型最大的不同就是其任务的切换,当遇到一个需要等待长时间执行的任务的时候,我们可以切换到其他的任务执行;
与多线程和多进程编程模型相比,异步编程只是在同一个线程之内的的任务调度,无法充分利用多核CPU的优势,所以特别适合IO阻塞性任务;
CompletableFuture理解
CompletableFuture的方法是比较重要的我们这边单独讲下: CompletableFuture 提供了四个静态方法来创建一个异步操作。 /** * Returns a new CompletableFuture that is asynchronously completed * by a task running in the {@link ForkJoinPool#commonPool()} with * the value obtained by calling the given Supplier. * * @param supplier a function returning the value to be used * to complete the returned CompletableFuture * @param <U> the function's return type * @return the new CompletableFuture */ public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) { return asyncSupplyStage(asyncPool, supplier); } /** * Returns a new CompletableFuture that is asynchronously completed * by a task running in the given executor with the value obtained * by calling the given Supplier. * * @param supplier a function returning the value to be used * to complete the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param <U> the function's return type * @return the new CompletableFuture */ public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) { return asyncSupplyStage(screenExecutor(executor), supplier); } /** * Returns a new CompletableFuture that is asynchronously completed * by a task running in the {@link ForkJoinPool#commonPool()} after * it runs the given action. * * @param runnable the action to run before completing the * returned CompletableFuture * @return the new CompletableFuture */ public static CompletableFuture<Void> runAsync(Runnable runnable) { return asyncRunStage(asyncPool, runnable); } /** * Returns a new CompletableFuture that is asynchronously completed * by a task running in the given executor after it runs the given * action. * * @param runnable the action to run before completing the * returned CompletableFuture * @param executor the executor to use for asynchronous execution * @return the new CompletableFuture */ public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) { return asyncRunStage(screenExecutor(executor), runnable); }
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)
supplyAsync :创建存在返回值的异步任务 callable 相当于创建一个线程池中submit中的参数是callable
runAsync:创建没有返回值的异步任务 runnable 相当于创建一个线程池中submit中的参数是runnable
注意点: 这两方法各有一个重载版本,可以指定执行异步任务的Executor实现,如果不指定,默认使用ForkJoinPool.commonPool(),如果机器是单核的,则默认使用ThreadPerTaskExecutor,该类是一个内部类,每次执行execute都会创建一个新线程。
概念理解结束之后我们通过下面的demo理解下:
package com.example; import java.util.Date; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class Deadlock { public static String str1 = "str1"; public static String str2 = "str1"; public static void main(String[] args) throws ExecutionException, InterruptedException { int i = 1; int ii = 2; int iii = 3; int iiii = 4; /*int j = i + ii; int jj = iii + iiii;*/ long t1 = System.currentTimeMillis(); //异步方法一 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->wc1(i, ii)); //异步方法二 CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(()->wc(iii,iiii)); // CompletableFuture.allOf 拿到全部返回的值 //CompletableFuture.anyOf 其中有多个值 只要返回其中一个 就继续执行下面的数据 CompletableFuture.allOf(future, future1); Integer j = future.get(); Integer jj = future1.get(); long t2 = System.currentTimeMillis(); System.out.println("运行时间 :" + (t2-t1)); //输出相关的内容 System.out.println(j); System.out.println(jj); } private static Integer wc(int i, int ii) { try { Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } int j = i + ii; System.out.println("睡了10秒 值:"+ j); return j; } private static Integer wc1(int i, int ii) { try { Thread.sleep(20000L); } catch (InterruptedException e) { e.printStackTrace(); } int j = i + ii; System.out.println("睡了20秒 值:"+ j); return j; } }
运行结果如下:
代码可能自己看不是那么好理解把代码放到自己的本地 运行debug看下就明白了
睡了10秒 值:7 睡了20秒 值:3 运行时间 :20079 3 7
allOf:当所有的CompletableFuture都执行完后执行计算
anyOf:最快的那个CompletableFuture执行完之后执行计算
只是初步了解学习;不足之处请多多指教;