异步编程探究JDK中的CompletableFuture(满足不同场景需求)

        CompletableFuture是一个通过编程方式显示地设置计算结果和状态以便让任务接收的Future,并且其可以作为一个CompletableStage(计算阶段),当它的计算完成时可以触发一个函数或者行为;当多个线程企图调用一个CompletableFuture的complete,cancel方发时只会有一个线程会成功。

        CompletableFuture除了含有可以直接操作任务状态和结果的方法外,还实现了CompletionStage接口的以下方法,这些方法遵循:

  •           当CompletableFuture任务完成后,同步使用任务执行线程来执行依赖任务结果的函数或者行为。
  •           所有异步的方法在没有显示指定Executor参数的情形下都是复用ForkJoinPool.commonPool()线程池来执行
  •           所有CompletionStage方法的实现都是相互独立的,以便一个方法的行为不会因为重载了其他方法而受影响

         一个CompletableFuture任务可能有一些依赖其计算结果的行为,这些行为方法被收集到一个无锁基于CAS操作为来链接起来的链表组成的栈中;当CompletableFuture的计算任务完成后,会自动弹出栈中的行为方法并执行。需要注意的是,由于是栈结构,在同一个CompletableFuture对象上作为注册的顺序与行为执行的顺序是相反的。

          由于默认情况下支撑CompletableFuture异步运行的是ForkJoinPool,所以这里我们有必要简单讲解下ForkJoinPool。ForkJoinPool本身也是一种ExecutorService,与其他ExecutorService相比,不同点是它使用了工作窃取算法来提升性能,其内部每个工作线程都关联自己的内存队列,正常情况下每个线程从自己队列里面获取任务并执行,当本身队列没有任务时,当前线程会去其他线程关联的队列里面获取任务来执行。这在很多任务会产生子任务或者有很多小的任务被提交到线程池来执行的情况下非常高效。

代码实例:

package org.jy.data.yh.bigdata.drools.asynchrono.domain;

/**
 * 天生线程安全的final类
 */
public final class UserDomain { // 打造一个线程安全的final类,只有get方法获取值,没有set方法修改值
    private final  String name;
    private final  int age;
    private final  String address;
    private final  String threadName;// 当前线程执行的名称

    public UserDomain(String initName,int initAge,String initAddress,String initThreadName) {  // 只用初始化内时,赋值的机会
        this.name = initName;
        this.age = initAge;
        this.address = initAddress;
        this.threadName = initThreadName;

    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public String getThreadName() {
        return threadName;
    }

    @Override
    public String toString() {
        return "UserDomain{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", threadName='" + threadName + '\'' +
                '}';
    }
}
package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import org.jy.data.yh.bigdata.drools.asynchrono.domain.UserDomain;
import java.util.concurrent.*;
/**
 *
 *显示设置CompletableFuture的结果(返回值)
 */
public class CompletableFuture1
{
    // 0 自定义线程池
    private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    private final static ThreadPoolExecutor POOL_EXECUTOR =   // 构建线程池对象
             new ThreadPoolExecutor(AVALIABLE_PROCESSORS,
            AVALIABLE_PROCESSORS*2,1, TimeUnit.MINUTES,
             new LinkedBlockingQueue<>(5),
             new ThreadPoolExecutor.CallerRunsPolicy());

    public static void main( String[] args ) throws ExecutionException, InterruptedException {
             // 1 创建一个CompletableFuture对象
        CompletableFuture<UserDomain> future = new CompletableFuture<UserDomain>();
        // 2 开启线程计算任务结果,并设置
        POOL_EXECUTOR.execute(()->{
            // 2.1休眠3s,模拟任务计算
            UserDomain userDomain = null;
            try {
                 userDomain = new UserDomain("张三",30,"北京海淀区",Thread.currentThread().getName());
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 2.2 设置计算结果到future

            System.out.println("----"+Thread.currentThread().getName()+"set future result------");
            future.complete(userDomain);
        });
        // 3 等待计算结果
        System.out.println("----main thread wait future result------");
        System.out.println("result : "+future.get());
        System.out.println("----main thread got future result-----");
        future.cancel(true);
        System.exit(0);  // 执行完成后自动退出,否则一直阻塞main线程,程序不会停止
    }
}

==================================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 *基于CompletableFuture实现异步计算与结果转换
 * 1)基于runAsync系列方法实现无返回值的异步计算:当你想异步执行一个任务,并且不需要任务的执行结果时可以使用该方法
 * 比如打印日志,异步做消息通知等
 */
public class CompletableFuture2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.1创建异步任务,并返回future
        CompletableFuture future = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() { // 2.2休眠2s模拟任务计算
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("over");
            }
        });
        // 1.3同步等待异步执行结果,null
        System.out.println(future.get());
        System.exit(0);
    }
}

==============================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import java.util.concurrent.*;

/**
 * 显示设置线程池:需要注意的是,在默认情况下,runAsyn(Runnable runnable)方法是使用整个JVM内唯一的ForkJoinPool.commonPool()线程池来执行任务的
 * 我们可以使用自己定制的线程池
 */
public class CompletableFuture3 {
    // 0 自定义线程池
    private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    private final static ThreadPoolExecutor POOL_EXECUTOR =   // 构建线程池对象
            new ThreadPoolExecutor(AVALIABLE_PROCESSORS,
                    AVALIABLE_PROCESSORS*2,1, TimeUnit.MINUTES,
                    new LinkedBlockingQueue<>(5),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.1创建异步任务,并返回future
        CompletableFuture future = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() { // 2.2休眠2s模拟任务计算
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("over");
            }
        });
        // 1.3同步等待异步执行结果,null
        System.out.println(future.get());
        System.exit(0);
    }
}

=========================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import org.jy.data.yh.bigdata.drools.asynchrono.domain.UserDomain;

import java.util.concurrent.*;
import java.util.function.Supplier;

/**
 * 基于supplyAsync系列方法实现有返回值的计算:
 * 当你 异步执行一个任务,并且需要任务的执行结果时,使用方法,比如
 * 异步对原始数据进行加工,并需要获取到被加工后的结果等
 */
public class CompletableFuture4 {
    // 0.创建线程池
    private static final ThreadPoolExecutor bizPoolExecutor =
            new ThreadPoolExecutor(8,8,1,
                    TimeUnit.MINUTES,new LinkedBlockingQueue<>(10));
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<UserDomain> result = CompletableFuture.supplyAsync(new Supplier<UserDomain>() {
            @Override
            public UserDomain get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                UserDomain result = new UserDomain("yanghong",28,"贵州贵阳",Thread.currentThread().getName());
                return result;
            }
        },bizPoolExecutor);
        // 2.2 同步等待异步任务执行结束
        System.out.println(result.get());
        System.exit(1);

    }

}

==============================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import org.jy.data.yh.bigdata.drools.asynchrono.domain.UserDomain;

import java.util.concurrent.*;
import java.util.function.Supplier;

/**
 * 基于thenRun实现异步任务A,执行完毕后,激活异步任务B执行,需要注意的是,这种方式激活的异步任务B
 * 是拿不到任务A执行的结果的
 */
public class CompletableFuture5 {
    // 0.创建线程池
    private static final ThreadPoolExecutor bizPoolExecutor =
            new ThreadPoolExecutor(8,8,1,
                    TimeUnit.MINUTES,new LinkedBlockingQueue<>(10));
    // thenRun不能访问oneFuture的结果
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建异步任务,并返回future
        CompletableFuture<UserDomain> oneFuture = CompletableFuture.supplyAsync(new Supplier<UserDomain>() {

            @Override
            public UserDomain get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                UserDomain result = new UserDomain("laogao",28,"天津",Thread.currentThread().getName());
                return result;
            }
        },bizPoolExecutor);
        // 2.在future上施加事件,当future计算完成后回调该事件,并返回新的future
        CompletableFuture twoFuture = oneFuture.thenRun(new Runnable() {
            @Override
            public void run() {
                // 当oneFuture任务计算完成后做一件事情
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 3 同步等待twoFuture对应的任务完成,返回结果固定为null
        System.out.println(twoFuture.get());
        System.exit(1);
    }
}

==================================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import org.jy.data.yh.bigdata.drools.asynchrono.domain.UserDomain;

import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 基于ThenAccept实现异步任务A,执行完毕后,激活异步任务B,需要注意的是,
 * 这种激活的异步B是可以拿到任务A的执行结果的
 */
public class CompletableFuture6 {
    // 0.创建线程池
    private static final ThreadPoolExecutor bizPoolExecutor =
            new ThreadPoolExecutor(8,8,1,
                    TimeUnit.MINUTES,new LinkedBlockingQueue<>(10));
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1,创建异步任务,并返回future
        CompletableFuture<UserDomain> oneFuture = CompletableFuture.supplyAsync(new Supplier<UserDomain>() {
            @Override
            public UserDomain get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                UserDomain result = new UserDomain("laoyang",28,"beijing",Thread.currentThread().getName());
                return result;
            }
        },bizPoolExecutor);
        // 2.在oneFuture上施加事件,当future计算完成后回调该事件,并返回新future
        CompletableFuture towFuture = oneFuture.thenAccept(new Consumer<UserDomain>() { // 消费者
            @Override
            public void accept(UserDomain userDomain) {
                // 2.1对oneFuture返回的结果进行加工
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("-----------------after oneFuture over doSomething-----"+userDomain);
            }
        });
        // 3同步等待towFuture对应的任务完成,返回结果固定为null
        System.out.println(towFuture.get());
        System.exit(1);
    }
}

=========================================================================================

package org.jy.data.yh.bigdata.drools.asynchrono.completablefuture;

import org.jy.data.yh.bigdata.drools.asynchrono.domain.UserDomain;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 *基于thenApply实现异步任务A,执行完毕后,激活异步任务B执行。
 * 需要注意的是,这种方式激活的异步任务B是可以拿到任务A的执行结果的,
 * 并且可以获得异步任务B的执行结果.
 */
public class CompletableFuture7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建异步任务,并返回future
        CompletableFuture oneFuture = CompletableFuture.supplyAsync(new Supplier<UserDomain>() {
            @Override
            public UserDomain get() {
                // 1.1休眠2s,模拟任务计算
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                UserDomain result = new UserDomain("laoyang",28,"beijing",Thread.currentThread().getName());
                return result;
            }
        });
        // 2,在future上施加事件,当future计算完成后回调该事件,并返回新的future
        CompletableFuture<Map<String,Object>> towFuture = oneFuture.thenApply(new Function<UserDomain,Map<String,Object>>() {

            @Override
            public Map<String,Object> apply(UserDomain userDomain) {
                Map result = new HashMap<String,Object>();
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                result.put("userKey",userDomain);
                result.put("randomKey",new Random().nextInt(10000));
                result.put("timeKey",System.currentTimeMillis());
                return result;
            }
        });
        // 3,同步等待towFuture对应的任务完成,并获取结果
        System.out.println("result: "+towFuture.get());
        System.exit(1);
    }
}

  

发布了74 篇原创文章 · 获赞 4 · 访问量 3181

猜你喜欢

转载自blog.csdn.net/u014635374/article/details/105512572