1.为什么使用线程池?
在没有线程池之前是我们是如何执行任务的
public class Task implements Runnable{
@Override
public void run() {
System.out.println("当前线程名称" + Thread.currentThread().getName());
}
}
@Test
public void threadDemo() {
/* 创建任务 */
Task task = new Task();
/* 创建线程 */
Thread thread = new Thread(task);
/* 启动线程 */
thread.start();
}
输出结果
当前线程名称Thread-1
如果我们想连续执行两个以上任务,那么我们就得重新对应数量的线程分别执行对应的任务。
@Test
public void threadDemo() {
/* 创建任务 */
Task task1 = new Task();
Task task2 = new Task();
Task task3 = new Task();
/* 创建线程 */
Thread thread = new Thread(task1);
Thread thread2 = new Thread(task2);
Thread thread3 = new Thread(task3);
/* 启动线程 */
thread.start();
thread2.start();
thread3.start();
}
输出结果
当前线程名称Thread-3
当前线程名称Thread-2
当前线程名称Thread-1
如果任务多起来就会很麻烦,因为上面线程不能复用,下面用线程池改造一下上面代码。
@Test
public void threadPoolDemo() {
/* 创建任务 */
Task task1 = new Task();
Task task2 = new Task();
Task task3 = new Task();
/* 创建只有一个任务的线程池线程 */
ExecutorService threadPool = Executors.newSingleThreadExecutor();
/* 启动任务 */
threadPool.execute(task1);
threadPool.execute(task2);
threadPool.execute(task3);
/* 关闭线程池 */
threadPool.shutdown();
}
输出结果
当前线程名称pool-2-thread-1
当前线程名称pool-2-thread-1
当前线程名称pool-2-thread-1
这样做的好处就是:
线程复用,避免线程的重复创建与销毁,降低了资源消耗;
当有任务时候不需要创建线程就能执行,提高响应速度;
可自行修改线程配置,灵活的管理线程。
2.使用原生方式创建线程池
2.1前述
ThreadPoolExecutor
是线程池的核心类,它一共有四个构造方法
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>, Threadfactory)
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>, ReiectedExecutionHandler)
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>, ThreadFactory, RejectedExecutionHandler)
下面会以上面最后一个构造方法为例演示
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
---核心线程数
线程池不关闭他就不会被销毁
keepAliveTime
---空闲线程存活时间
如果在规定时间内没有任务,那么会销毁非核心线程
unit
---时间单位
workQueue
---任务队列
存放任务的容器,常见有ArrayBlockingQueue(数组阻塞队列)和LinkedBlockingDeque(链式阻塞队列)等其他
threadFactory
---线程工厂
它是一个接口
通过实现这个接口可以可以定义线程的相关设置,比如
指定线程名称
public class MyThread implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
/* 创建线程并指定任务 */
Thread thread = new Thread(r);
/* 设置线程名称 */
thread.setName("自定义线程" + thread.getId() + "---");
return thread;
}
}
@Test
public void threadPoolDemo2() {
/* 创建任务 */
Task task1 = new Task();
Task task2 = new Task();
Task task3 = new Task();
/* 创建只有一个任务的线程池线程 */
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10,
25,
10,
TimeUnit.SECONDS,
new java.util.concurrent.ArrayBlockingQueue<>(10),
new MyThread(),
new ThreadPoolExecutor.AbortPolicy()
);
/* 启动任务 */
threadPoolExecutor.execute(task1);
threadPoolExecutor.execute(task2);
threadPoolExecutor.execute(task3);
/* 关闭线程池 */
threadPoolExecutor.shutdown();
}
输出结果
当前线程名称自定义线程31---
当前线程名称自定义线程33---
当前线程名称自定义线程32---
handler
---任务拒绝策略
ps:绿色为核心线程,黄色为非核心线程,最大核心线程为25
如果同时满足以下四种情况,我们提交给线程池的任务会被拒绝。
1.线程池中线程已满;
2.无法再继续扩容;
3.没有空闲的线程,所有线程都在执行任务;
4.任务队列已满,无法再存入新任务;
线程池拒绝策略也有四种
2.2原生线程池创建示例
2.21自定义一个线程工厂
public class CustomThreadFactory implements ThreadFactory {
/* 计数器 */
private final AtomicInteger count = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
/* 创建线程并指定任务 */
Thread thread = new Thread(r);
/* 设置线程名称 */
thread.setName("自定义" + count + "号线程---");
return thread;
}
}
2.22创建一个任务
public class Task implements Runnable{
@Override
public void run() {
System.out.println("当前线程名称" + Thread.currentThread().getName());
}
}
2.23创建线程池执行刚才的任务
@Test
public void threadPoolDemo2() {
/* 创建任务 */
Task task1 = new Task();
Task task2 = new Task();
Task task3 = new Task();
/* 创建只有一个任务的线程池线程 */
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10,
25,
10,
TimeUnit.SECONDS,
new java.util.concurrent.ArrayBlockingQueue<>(10),
new CustomThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
/* 启动任务 */
threadPoolExecutor.execute(task1);
threadPoolExecutor.execute(task2);
threadPoolExecutor.execute(task3);
/* 关闭线程池 */
threadPoolExecutor.shutdown();
}
输出结果
当前线程名称自定义3号线程---
当前线程名称自定义1号线程---
当前线程名称自定义2号线程---
评论区