Java多线程-并行处理以及事务控制

1.为了提高我们接口的响应速度,我们可以开多个线程,并行处理,比如我们要大批量写入数据到数据库

	@Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private PlatformTransactionManager transactionManager;

    private List<TransactionStatus> transactionStatuses = Collections.synchronizedList(new ArrayList<TransactionStatus>());
    
	//采用二阶段提交模式,分布式事务思想
    @Override
    public void tx2PC() {
        List<Integer> addList = new ArrayList<>();
        //要写入的数据
        for (int i = 0; i < 2000; i++) {
            addList.add(i);
        }
        //切分新增集合
        List<List<Integer>> partitions = Lists.partition(addList, 800);

        //定义局部变量,是否成功、顺序标识、等待线程队列
        AtomicBoolean isError = new AtomicBoolean(false);
        List<Thread> unfinishedList = new ArrayList<>();
        AtomicInteger cur = new AtomicInteger(1);

        int totalSize = partitions.size();

        CompletableFuture<Void> future = CompletableFuture.allOf(
                partitions.stream().map(partition ->
                        CompletableFuture.runAsync(() -> {
                            //Spring事务内部由ThreadLocal存储事务绑定信息,因此需要每个线程新开一个事务
                            TransactionStatus transactionStatus = beginNewTransaction();
                            int curInt = cur.getAndIncrement();
                            try {
                                log.info("当前是第{}个线程开始启动,线程名={}", curInt, Thread.currentThread().getName());
                                //ArrayList线程不安全,多线程会出现数据覆盖,体现为数据丢失
                                synchronized (unfinishedList) {
                                    unfinishedList.add(Thread.currentThread());
                                }
                                log.info("当前是第{}个线程已加入队列,开始休眠,线程名={}", curInt, Thread.currentThread().getName());

                                //写入数据
                                insert2(1);
                                insert3(1);
                                //尝试唤醒所有线程
                                notifyAllThread(unfinishedList, totalSize, false);
                                //让当前线程挂起,
                                LockSupport.park();
                                if (isError.get()) {
                                    log.info("当前是第{}个线程回滚,线程名={}", curInt, Thread.currentThread().getName());
                                    transactionManager.rollback(transactionStatus);
                                } else {
                                    log.info("当前是第{}个线程提交,线程名={}", curInt, Thread.currentThread().getName());
                                    transactionManager.commit(transactionStatus);
                                }

                            } catch (Exception e) {
                                log.error("当前是第{}个线程出现异常,线程名={}", curInt, Thread.currentThread().getName(), e);
                                transactionManager.rollback(transactionStatus);
                                e.printStackTrace();
                                isError.set(true);
                                //唤醒所有线程
                                notifyAllThread(unfinishedList, totalSize, true);
                            }
                        }, executor)).toArray(CompletableFuture[]::new));

        //阻塞主线程
        future.join();

    }

    private void notifyAllThread(List<Thread> unfinishedList, int totalSize, boolean isForce) {
        if (isForce || unfinishedList.size() >= totalSize) {
            log.info("唤醒当前所有休眠线程,线程数={},总线程数={},是否强制={}", unfinishedList.size(), totalSize, isForce);
            for (Thread thread : unfinishedList) {
                log.info("当前线程={}被唤醒", thread.getName());
                LockSupport.unpark(thread);
            }
        }
    }

    private TransactionStatus beginNewTransaction() {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。
        TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
        return status;
    }

	

你可能感兴趣的:(多线程,java,多线程,事务)