异步方法 理解(demo附代码)

简介: 异步方法 理解(demo附代码)

异步方法是什么?


每次启动程序时,系统会⾃动在内存中创建⼀个进程。进程是构成运⾏程序的资源的集合。这些资源包括虚地址空间、⽂件句柄和许多其他程序运 ⾏所需的资源。 在进程的内部,系统会创建⼀个称为线程的内核(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执行完之后执行计算


只是初步了解学习;不足之处请多多指教;

相关文章
|
3月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
188 1
|
6月前
|
C#
C#学习系列相关之多线程(四)----async和await的用法
C#学习系列相关之多线程(四)----async和await的用法
方法的概念理解和demo
方法的概念理解和demo
66 0
|
6月前
|
存储 C++
【C++】function包装器全解(代码演示,例题演示)
【C++】function包装器全解(代码演示,例题演示)
对于async和await的使用方式、作用效果不怎么理解 ?没关系,初步看这篇就够了
对于async和await的使用方式、作用效果不怎么理解 ?没关系,初步看这篇就够了
|
前端开发
前端学习案例2-aysnc和await之co+生成器2
前端学习案例2-aysnc和await之co+生成器2
78 0
前端学习案例2-aysnc和await之co+生成器2
|
前端开发
前端学习案例1-aysnc和await之co+生成器1
前端学习案例1-aysnc和await之co+生成器1
88 0
前端学习案例1-aysnc和await之co+生成器1
|
前端开发
前端学习案例25-aysnc和await之1
前端学习案例25-aysnc和await之1
80 0
前端学习案例25-aysnc和await之1
|
前端开发
前端学习案例26-aysnc和await之2
前端学习案例26-aysnc和await之2
75 0
前端学习案例26-aysnc和await之2
下一篇
无影云桌面