java 异步学习使用

104 阅读6分钟

1.概念 及 代码地址

概念:
    事情之间相对独立,A、B、C三个事情各自执行,A执行完之后回调或者通知B,B执行完之后回调或者通知C,在各自拿到其他事情的结果之前,可以先处理自己那部分的事情,这个过程叫做异步。
    
代码地址:
    study-thread/src/main/java/cn/zy/study/thread/threadAsyn

2.参考文章

1.实现异步的 8 种方式,收藏起来
    https://mp.weixin.qq.com/s/S53SK-Yy7OPnm-S_CdtymA  
2. Java8 异步非阻塞做法:CompletableFuture 两万字详解!
    https://mp.weixin.qq.com/s/dTxicKhZq_BXwcMne8mq7g

3.异步的几种实现方式

1.  线程Thread
2.  Future
3.  异步框架CompletableFuture *******
4.  Spring注解@Async *******
5.  Spring ApplicationEvent事件
6.  消息队列
7.  第三方异步框架,比如Hutool的ThreadUtil
8.  Guava异步

4.列举用到的实践方式

4.1.Spring注解@Async

业务逻辑类

package cn.zy.study.thread.threadAsyn;

import cn.hutool.extra.spring.SpringUtil;
import cn.zy.study.common.utils.date.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

@Service
@Slf4j
public class TransctionService2 {

    @Autowired
    ShWhRepository shWhRepository;

    @Autowired
    AsyncService2 asyncService2;

    /**
     * 当前service报错 异步方法不报错
     */
    @Transactional(rollbackFor = Exception.class)
    public void serviceFallAsync1() throws Exception {
        log.info("=======================TransctionService2 serviceFallAsync1 开始执行");
        System.out.println("=======================线程名称:" + Thread.currentThread().getName());
        ShWh shWh = new ShWh();
        shWh.setOrgId(1000L)
                .setWh("仓库代码")
                .setWhName("仓库名称")
                .setWhType("仓库类型")
                .setValuationMode("计价方式")
                .setStorageMode("存储方式")
                .setIsUsed(true).setWhAttr("仓库属性")
                .setEnabled(false)
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("6666")
                .setUpdateUser("6666").setUpdateTime(DateUtils.getTimestamp());

        /**
         * 主线程事物异常回滚不影响异步的事物
         */
/*      int a = 1 / 0;//报错下方代码不执行
        shWhRepository.save(shWh);
        asyncService2.serviceFallAsync1();
        */

/*      shWhRepository.save(shWh);//回滚
        int a = 1 / 0;
        asyncService2.serviceFallAsync1();//不执行
        */

/*      shWhRepository.save(shWh);//回滚
        asyncService2.serviceFallAsync1();//保存到数据库 不回滚
        int a = 1 / 0;
        */


        /**
         *  1.异步方法有返回值----->主线程接收返回值调用get后 主线程拿到异步抛出的异常 主线程事物回滚,异步事物不受影响
         */
/*        //两条数据都保存到数据库
        asyncService2.serviceFallAsync3();//保存后 异常未抛出到当前方法 控制台未打印
        shWhRepository.save(shWh);//正常执行保存到数据库*/

/*        //1条数据保存成功(异步保存成功)
        Future<String> stringFuture = asyncService2.serviceFallAsync3();//保存成功
        stringFuture.get();//异步异常抛出到当前方法
        shWhRepository.save(shWh);//不执行 或者执行后 事务回滚*/


        /**
         *  1.异步方法无返回值----->异步方法的异常不影响主线程正常执行
         */
/*        //1条数据都保存成功
        shWhRepository.save(shWh);//保存成功 未捕获到异步的异常 事物未回滚
        asyncService2.serviceFallAsync4();//异步方法事物生效 回滚 控制台报异常*/

/*        //1条数据都保存成功
        asyncService2.serviceFallAsync4();//事物回滚 控制台报异常
        shWhRepository.save(shWh);//保存成功 未捕获到异步的异常事物未回滚*/


        /**
         * 异步方法 try cach 抛出异常 手动控制事物
         */
        /*//保存成功一条数据
        asyncService2.serviceFallAsync2();//异步方法手动控制事物 报错后事物回滚
        shWhRepository.save(shWh);//正常保存数据*/

/*        //保存成功一条数据
        shWhRepository.save(shWh);//保存成功 异步抛出的事物未掉用get() 当前方法未拿到异常
        asyncService2.serviceFallAsync2();//异步方法手动控制事物 报错后事物回滚*/


        /**
         * 事务 异步 最终用法1 如下
         */
        //保存0条数据
        shWhRepository.save(shWh);// 异步的异常抛出到当前方法 当前方法事物生效  数据回滚
        Future<String> stringFuture = asyncService2.serviceFallAsync2();//异步方法手动控制事物 报错后事物回滚
        stringFuture.get();
    }

    @Autowired
    ThreadPoolTaskExecutor myTaskAsyncPool;

    /**
     * 事务 异步 最终用法2 如下
     */
    @Transactional(rollbackFor = Exception.class)
    public void completableFuture() {
        ShWh shWh2 = new ShWh();
        shWh2.setOrgId(1000L)
                .setWh("仓库代码")
                .setWhName("仓库名称")
                .setWhType("仓库类型")
                .setValuationMode("计价方式")
                .setStorageMode("存储方式")
                .setIsUsed(true).setWhAttr("仓库属性")
                .setEnabled(false)
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("6666")
                .setUpdateUser("6666").setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh2);
        System.out.println("当前线程名称" + Thread.currentThread().getName());
        CompletableFuture<ShWh> userFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程名称" + Thread.currentThread().getName());
            PlatformTransactionManager txManager = SpringUtil.getBean(PlatformTransactionManager.class);
            TransactionStatus txStatus = txManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
            ShWh shWh = new ShWh();
            shWh.setOrgId(111L)
                    .setWh("仓库代码")
                    .setWhName("仓库名称")
                    .setWhType("仓库类型")
                    .setValuationMode("计价方式")
                    .setStorageMode("存储方式")
                    .setIsUsed(true).setWhAttr("仓库属性")
                    .setEnabled(false)
                    .setCreateTime(DateUtils.getTimestamp())
                    .setCreateUser("6666")
                    .setUpdateUser("6666").setUpdateTime(DateUtils.getTimestamp());
            shWh = shWhRepository.save(shWh);
            //有了下边的代码异步中的事物才能回滚
            try {
                Thread.sleep(1000L);
                int a = 1 / 0;
                txManager.commit(txStatus);
            } catch (Exception e) {
                txManager.rollback(txStatus);
                throw new RuntimeException(e);
            }
            return shWh;
        }, myTaskAsyncPool);
        //下边一行代码起到线程阻塞作用(//allOf:等待所有任务完成   | anyOf:只要有一个任务完成)
        CompletableFuture.allOf(userFuture).join();//掉用后异步的异常才能触发 - 抛出到当前主线程
        System.out.println("130行代码执行");
        System.out.println("执行完成");
    }
}


异步方法类

package cn.zy.study.thread.threadAsyn;

import cn.hutool.extra.spring.SpringUtil;
import cn.zy.study.common.utils.date.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.concurrent.Future;

/**
 * 异步的方法服务类
 */
@Component
@Slf4j
public class AsyncService2 {

    @Autowired
    ShWhRepository shWhRepository;


    /**
     * 有返回值 无异常
     *
     * @return
     * @throws Exception
     */
    @Async("myTaskAsyncPool")
    public Future<String> serviceFallAsync1() throws Exception {
        log.info("====================AsyncService2 serviceFallAsync1 开始执行");
        System.out.println("=======================线程名称:" + Thread.currentThread().getName());
        ShWh shWh = new ShWh();
        shWh.setOrgId(2000L)
                .setWh("仓库代码2")
                .setWhName("仓库名称2")
                .setWhType("仓库类型2")
                .setValuationMode("计价方式2")
                .setStorageMode("存储方式2")
                .setIsUsed(true)
                .setEnabled(false)
                .setWhAttr("仓库属性2")
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("8888")
                .setUpdateUser("8888")
                .setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh);
        log.info("====================AsyncService2 serviceFallAsync1 执行结束");
        return new AsyncResult<String>("serviceFallAsync1 success");
    }


    /**
     * 无返回值 保存数据库后抛异常
     *
     * @throws Exception
     */
    @Async("myTaskAsyncPool")
    public void serviceFallAsync4() throws Exception {
        log.info("====================AsyncService2 serviceFallAsync2 开始执行");
        System.out.println("=======================线程名称:" + Thread.currentThread().getName());
        PlatformTransactionManager txManager = SpringUtil.getBean(PlatformTransactionManager.class);
        TransactionStatus txStatus = txManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
        ShWh shWh = new ShWh();
        shWh.setOrgId(2000L)
                .setWh("仓库代码2")
                .setWhName("仓库名称2")
                .setWhType("仓库类型2")
                .setValuationMode("计价方式2")
                .setStorageMode("存储方式2")
                .setIsUsed(true)
                .setEnabled(false)
                .setWhAttr("仓库属性2")
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("8888")
                .setUpdateUser("8888")
                .setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh);
        try {
            int a = 1 / 0;
            txManager.commit(txStatus);
        } catch (Exception e) {
            txManager.rollback(txStatus);
            throw new RuntimeException();
        }
        log.info("====================AsyncService2 serviceFallAsync2 执行结束");
    }

    /**
     * 有返回值 保存数据后抛异常
     *
     * @return
     * @throws Exception
     */
    @Async("myTaskAsyncPool")
    public Future<String> serviceFallAsync3() throws Exception {
        log.info("====================AsyncService2 serviceFallAsync3 开始执行");
        System.out.println("=======================线程名称:" + Thread.currentThread().getName());
        ShWh shWh = new ShWh();
        shWh.setOrgId(2000L)
                .setWh("仓库代码2")
                .setWhName("仓库名称2")
                .setWhType("仓库类型2")
                .setValuationMode("计价方式2")
                .setStorageMode("存储方式2")
                .setIsUsed(true)
                .setEnabled(false)
                .setWhAttr("仓库属性2")
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("8888")
                .setUpdateUser("8888")
                .setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh);
        int a = 1 / 0;
        log.info("====================AsyncService2 serviceFallAsync3 执行结束");
        return new AsyncResult<String>("serviceFallAsync3 success");
    }

    /**
     * 有返回值 方法捕获异常 手动
     *
     * @return
     * @throws Exception
     */
    @Async("myTaskAsyncPool")
    public Future<String> serviceFallAsync2() throws Exception {
        log.info("====================AsyncService2 serviceFallAsync2 开始执行");
        System.out.println("=======================线程名称:" + Thread.currentThread().getName());
        PlatformTransactionManager txManager = SpringUtil.getBean(PlatformTransactionManager.class);
        TransactionStatus txStatus = txManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
        ShWh shWh = new ShWh();
        shWh.setOrgId(2000L)
                .setWh("仓库代码2")
                .setWhName("仓库名称2")
                .setWhType("仓库类型2")
                .setValuationMode("计价方式2")
                .setStorageMode("存储方式2")
                .setIsUsed(true)
                .setEnabled(false)
                .setWhAttr("仓库属性2")
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("8888")
                .setUpdateUser("8888")
                .setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh);
        try {
            int a = 1 / 0;
            txManager.commit(txStatus);
        } catch (Exception e) {
            txManager.rollback(txStatus);
            log.error("exception:{}", e.getMessage());
            e.printStackTrace();
            throw new RuntimeException();
        }

        log.info("====================AsyncService2 serviceFallAsync2 执行结束");
        return new AsyncResult<String>("serviceFallAsync2 success");
    }


}

junit测试类

package cn.zy.study.thread.threadAsyn;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@Slf4j
public class TransctionService2Test {
    //================================ service ----->async
    @Autowired
    TransctionService2 transctionService2;

    @Test
    public void serviceFallAsyncTest1() throws Exception {
        transctionService2.serviceFallAsync1();
    }
    @Test
    public void completableFutureTest1() throws Exception {
        transctionService2.completableFuture();
    }
}

5.异步框架CompletableFuture 使用

//参考:https://mp.weixin.qq.com/s/dTxicKhZq_BXwcMne8mq7g
@Transactional(rollbackFor = Exception.class)
public void completableFuture() {
        ShWh shWh2 = new ShWh();
        shWh2.setOrgId(1000L)
                .setWh("仓库代码")
                .setWhName("仓库名称")
                .setWhType("仓库类型")
                .setValuationMode("计价方式")
                .setStorageMode("存储方式")
                .setIsUsed(true).setWhAttr("仓库属性")
                .setEnabled(false)
                .setCreateTime(DateUtils.getTimestamp())
                .setCreateUser("6666")
                .setUpdateUser("6666").setUpdateTime(DateUtils.getTimestamp());
        shWhRepository.save(shWh2);
        System.out.println("当前线程名称" + Thread.currentThread().getName());
        CompletableFuture<ShWh> userFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程名称" + Thread.currentThread().getName());
            PlatformTransactionManager txManager = SpringUtil.getBean(PlatformTransactionManager.class);
            TransactionStatus txStatus = txManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));
            ShWh shWh = new ShWh();
            shWh.setOrgId(111L)
                    .setWh("仓库代码")
                    .setWhName("仓库名称")
                    .setWhType("仓库类型")
                    .setValuationMode("计价方式")
                    .setStorageMode("存储方式")
                    .setIsUsed(true).setWhAttr("仓库属性")
                    .setEnabled(false)
                    .setCreateTime(DateUtils.getTimestamp())
                    .setCreateUser("6666")
                    .setUpdateUser("6666").setUpdateTime(DateUtils.getTimestamp());
            shWh = shWhRepository.save(shWh);
            //有了下边的代码异步中的事物才能回滚
            try {
                Thread.sleep(1000L);
                int a = 1 / 0;
                txManager.commit(txStatus);
            } catch (Exception e) {
                txManager.rollback(txStatus);
                throw new RuntimeException(e);
            }
            return shWh;
        }, myTaskAsyncPool);
        //下边一行代码起到线程阻塞作用(//allOf:等待所有任务完成   | anyOf:只要有一个任务完成)
        CompletableFuture.allOf(userFuture).join();//掉用后异步的异常才能触发 - 抛出到当前主线程
        System.out.println("130行代码执行");
        System.out.println("执行完成");
    }