spring 异步和多线程,线程池/事务/进度/并发

配置线程池

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Excel任务执行器
 *
 */
@Configuration
@ComponentScan("com.schedule.application.task")  //异步扫描的作用域
@EnableAsync  //开启异步也就是启动线程
public class ExcelTaskExecutorConfig implements AsyncConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(ExcelTaskExecutorConfig.class);

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(15);  //最大线程数
        taskExecutor.setCorePoolSize(10); 
        taskExecutor.setQueueCapacity(30);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();

        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> logger.error("Async Exception:", throwable);
    }
}

2.使用,这里注意两问题,
a.如果async和transaction同时注解在Service方法里,会出现拿不到spring的bean,解决方法看 Task1
b.如果是分开使用,就没有问题 Task2

@Service
@EnableAspectJAutoProxy(exposeProxy = true)  //开启代理
public class Task1 {
	//最大线程处理的数据量
	private final int PAGE_SIZE = 400;
	//并发计数
    private AtomicInteger count;

    @Async
    public void batchUpdate() throws Exception {
		List<XXX> list = testService.getList();
		int total = list.size();
        int pageTotal = getPageTotal(total);
		count = new AtomicInteger(0);
		TestService task = (TestService) AopContext.currentProxy();  //service的方法只能通过代理拿到
		for (int i = 0; i < pageTotal; i++) {
			List<XXX> pageList = list.stream().skip(i * PAGE_SIZE).limit(PAGE_SIZE).collect(Collectors.toList());
			task.doData1(pageList,count);
		}
	
	}
	private int getPageTotal(int dataSize) {
		int pageTotal = 0;
		if (dataSize == 0) {
			return pageTotal;
		}

		if (dataSize % PAGE_SIZE == 0) {
			pageTotal = dataSize / PAGE_SIZE;
		} else {
			pageTotal = dataSize / PAGE_SIZE + 1;
		}
		return pageTotal;
	}
}
@Service
public class Task2 {
	//最大线程处理的数据量
	private final int PAGE_SIZE = 400;
	//并发计数
    private AtomicInteger count;
	@Autowired
	private TestService testService;

    @Async
    public void batchUpdate() throws Exception {
		List<XXX> list = testService.getList();
		int total = list.size();
        int pageTotal = getPageTotal(total);
		count = new AtomicInteger(0);
		
		for (int i = 0; i < pageTotal; i++) {
			List<XXX> pageList = list.stream().skip(i * PAGE_SIZE).limit(PAGE_SIZE).collect(Collectors.toList());
			testService.doData2(pageList,count);
		}
	}
	private int getPageTotal(int dataSize) {
		同上
	}
}
@Service
public class TestService{

	private ReentrantLock lock = new ReentrantLock();

	public List<XXX> getList(){
		...
	}
	
	@Async
	@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public void doData1(List<XXX> list,AtomicInteger count){
		... 处理数据,更新、添加、想干嘛干嘛
		//更新进度
		lock.lock();
		
		try {
			int size = count.addAndGet(list.size());
            double hand = 100D;
            double percent = (double) size / (double) total * hand;
            String remark = "处理多少:" + size + ",总共:" + total;
			//更新进度 到数据库
			
		} finally {
            lock.unlock();
        }
	}
	
	
	@Async
    @Override
    public void doData2(List<XXX> list,AtomicInteger count){
		...同上
		..这里如果更新,添加需要到具体的Service中添加事务注解
	}
}

你可能感兴趣的:(java)