目录
一、线程池概念
二、线程池重要参数
三、使用线程池的注意事项
四、使用场景及示例代码
从字面上理解它就是一个管理线程的池子。
TimeUnit.DAYS; 天
TimeUnit.HOURS; 小时
TimeUnit.MINUTES; 分钟
TimeUnit.SECONDS; 秒
TimeUnit.MILLISECONDS; 毫秒
TimeUnit.MICROSECONDS; 微秒
TimeUnit.NANOSECONDS; 纳秒
创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。
corePoolSize、workQueue、maximumPoolSize都不可用的时候执行的饱和策略。
线程池尽量不要使用的时候再创建,不要在业务逻辑里面去创建线程池,因为这样会在每次调用这个方法的时候,都会创建一个线程池。应该在项目启动的时候,就把线程池创建好。
1、任务来了,直接将任务交给线程池去做,至于成不成功、用不用返回值,不去关注。
主要适用于一些更新操作,此操作不用过于关注执行结果或返回值。
代码:起一个springboot项目
①写一个线程池配置类,加上@Configuration将线程池交给spring去管理
import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
* 线程池配置
*
* @author yunyan
* @date 2023/7/8
*/
@Configuration
public class ThreadPoolConfig {
public static final String NAME_PRE="test";
@Bean
public static ExecutorService getExecutor(){
return ExecutorBuilder.create()
.setCorePoolSize(8)
.setMaxPoolSize(16)
.setKeepAliveTime(60, TimeUnit.SECONDS)
.setWorkQueue(new LinkedBlockingQueue<>(2000))
.setHandler(new ThreadPoolExecutor.CallerRunsPolicy())
.setAllowCoreThreadTimeOut(false)
.setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix(NAME_PRE).build())
.build();
}
}
②service层:
/**
* 用户服务
*
* @author yunyan
* @date 2023/5/29
*/
public interface IUserService extends IService {
/**
* 测试线程池
*/
void testThreadPool();
}
③service实现类:
/**
* 用户服务impl
*
* @author yunyan
* @date 2023/5/29
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl implements IUserService {
//通过Resource注解将ExecutorService 的实现类也就是ThreadPoolConfig 中getExecutor返回的线程池对象。
@Resource
private ExecutorService executorService;
@Override
public void testThreadPool(){
log.info("我来啦");
/**模拟业务场景耗时操作**/
//交给线程池的线程去执行
CompletableFuture.runAsync(()->{
try {
log.info("我真的来啦");
Thread.sleep(10000);
log.info("我是10s后执行的");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},executorService);
}
④controller层:
@GetMapping("/open/test")
public ResultUtil test(){
userService.testThreadPool();
return ResultUtil.success(Boolean.TRUE);
}
⑤结果
通过浏览器访问接口,不需要等待10s,结果直接返回浏览器。
2、任务来了,将任务交给线程池去执行,等任务都执行完了 ,主线程才能解除阻塞。
适用于:
需要循环调用http接口查询
需要for循环查询数据库
①执行结果BO类
import lombok.Data;
/**
* 查询
*
* @author yunyan
* @date 2023/7/8
*/
@Data
public class QueryBO {
private Boolean query1;
private Boolean query2;
private Boolean query3;
}
②线程池配置类
import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
* 线程池配置
*
* @author yunyan
* @date 2023/7/8
*/
@Configuration
public class ThreadPoolConfig {
public static final String NAME_PRE="test-";
@Bean("testThreadPool")
public static ExecutorService getExecutor(){
return ExecutorBuilder.create()
.setCorePoolSize(8)
.setMaxPoolSize(16)
.setKeepAliveTime(60, TimeUnit.SECONDS)
.setWorkQueue(new LinkedBlockingQueue<>(2000))
.setHandler(new ThreadPoolExecutor.CallerRunsPolicy())
.setAllowCoreThreadTimeOut(false)
.setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix(NAME_PRE).build())
.build();
}
}
③service层:
/**
* 用户服务
*
* @author yunyan
* @date 2023/5/29
*/
public interface IUserService extends IService {
/**
* 测试线程池
*/
void testThreadPool();
}
④service实现类
/**
* 用户服务impl
*
* @author yunyan
* @date 2023/5/29
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl implements IUserService {
//通过Resource注解将ExecutorService 的实现类也就是ThreadPoolConfig 中getExecutor返回的线程池对象。
@Resource
private ExecutorService executorService;
@Override
public void testThreadPool(){
log.info("我来啦");
QueryBO queryBO=new QueryBO();
//查看当前的时间戳
long start = System.currentTimeMillis();
CompletableFuture query1 = CompletableFuture.runAsync(() -> {
Boolean aBoolean = null;
try {
aBoolean = query1();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
queryBO.setQuery1(aBoolean);
}, executorService);
CompletableFuture query2 = CompletableFuture.runAsync(() -> {
Boolean aBoolean = null;
try {
aBoolean = query2();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
queryBO.setQuery2(aBoolean);
}, executorService);
CompletableFuture query3 = CompletableFuture.runAsync(() -> {
Boolean aBoolean = null;
try {
aBoolean = query3();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
queryBO.setQuery3(aBoolean);
}, executorService);
/**将上面的三个任务放到数组中**/
CompletableFuture[] completableFutures= Stream.of(query1,query2,query3).collect(Collectors.toList()).toArray(new CompletableFuture[3]);
/**相当于阻塞的过程**/
CompletableFuture.allOf(completableFutures).join();
//查看时间差
long time=System.currentTimeMillis()-start;
log.info("查询结果{},时间是{}",queryBO,time);
}
public Boolean query1() throws InterruptedException {
log.info("这是1");
Thread.sleep(3000);
return true;
}
public Boolean query2() throws InterruptedException {
log.info("这是2");
Thread.sleep(1000);
return true;
}
public Boolean query3() throws InterruptedException {
log.info("这是3");
Thread.sleep(5000);
return true;
}
}
⑤controller
@GetMapping("/open/test")
public ResultUtil test(){
userService.testThreadPool();
return ResultUtil.success(Boolean.TRUE);
}
⑥结果
通过调用接口可以发现三个任务是同时进行的,5s后,结果才返回给浏览器
通过日志可以观察到,这三个任务由原来串行化执行9s变为多线程并行执行5s