java 多线程的用处,如异步处理,多线程同步数据等
通常我们的做法是使用Executors来创建线程池,因为他可以做到统一管理,有效的控制最大并发线程防止new Thread() 产生的线程恶性竞争等问题;
Executors 的4 种线程池
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newFixedThreadPool
创建一个可缓存线程池,应用中存在的线程数可以无限大
newCachedThreadPool
创建一个定长线程池,支持定时及周期性任务执行
newScheduledThreadPool
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
newSingleThreadExecutor
下面使用定长线程池同步一万条数据:
/**
* @version 1.0
* @author: lsy
* @create: 2021-06-01 11:19
**/
public class ThreadTest {
//每个线程分配的数据量
private static final Integer VALUE = 1000;
/**
* 这里我们使用固定线程数的线程池同步数据
* 举例生成一万条数据,分给5个线程,每个线程处理1000条数据
* 线程全部使用时则等待
*
* @param args
*/
public static void main(String[] args) {
//创建一万条测试数据
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add("测试数据" + i);
}
//创建线程池(固定线程数=5)
ExecutorService executor = Executors.newFixedThreadPool(5);
int formIndex = 0; //切割list的fromIndex
while (true) {
//切割list 的toIndex (如果toIndex值没有超过list的总大小,则使用list的size)
int toIndex = Math.min((formIndex + VALUE), list.size());
List<String> strings = list.subList(formIndex, toIndex);
//如果线程没有关闭
if (!executor.isShutdown()) {
executor.execute(runnable(strings));
}
//下一次的 结束值值=本次的开始值
formIndex = toIndex;
if (formIndex >= list.size()) {
break;
}
}
//关闭线程池
executor.shutdown();
}
/**
* 进入线程方法
*
* @param list
* @return
*/
public static Runnable runnable(List list) {
return new Runnable() {
@Override
public void run() {
insert(list);
}
};
}
/**
* 入库方法
*
* @param list
*/
private static void insert(List list) {
for (int i = 0; i < list.size(); i++) {
String o = (String) list.get(i);
System.out.println(o);
}
}
}
在实际项目中通常线程类已经设置好,比如核心线程数,最大线程数,线程阻塞策略等
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@EnableAsync
@Configuration
public class ThreadPoolConfig {
private static Logger log = LoggerFactory.getLogger(ThreadPoolConfig.class);
/***
* 重要任务执行
* Date 2021/6/8 14:15
* @author lsy
* @param []
* @return java.util.concurrent.Executor
*/
@Bean("timingPool")
public Executor getTimingPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置线程的核心线程数 (读取cpu核心,使用cpu核心个数作为线程数)
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
//设置线程最大线程数 (读取cpu核心,使用cpu核心数*2作为最大线程数)
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// use SynchronousQueue
//设置阻塞队列的容量 (不使用阻塞队列)
executor.setQueueCapacity(0);
// 设置线程池允许的空闲时间(默认为60秒)
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("timingPool-");
executor.setRejectedExecutionHandler((r, e) -> {
log.warn("timing pool can't schedule job immediately, maybe some job using too much cpu times.");
// 定时任务优先级较高,不惜一些代价都需要继续执行,开线程继续干~
new Thread(r).start();
});
return executor;
}
/***
* 普通任务执行
* Date 2021/6/8 14:15
* @author lsy
* @param []
* @return java.util.concurrent.Executor
*/
@Bean("commonPool")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置线程的核心线程数 (读取cpu核心,使用cpu核心个数作为线程数)
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
//设置线程最大线程数 (读取cpu核心,使用cpu核心个数作为线程数)
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());
//设置阻塞队列的容量
executor.setQueueCapacity(1024);
// 设置线程池允许的空闲时间(默认为60秒)
executor.setKeepAliveSeconds(180);
executor.setThreadNamePrefix("commonPool-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
直接注入使用就好
@Resource(name = "commonPool")
private Executor commonPool;