Q:什么是线程池?
A:线程池是指在应用程序中创建一个线程集合,然后在执行任务时重用这些线程而不是重新创建新的线程.线程池中的线程数量取决于处理器数目和工作队列的性质,通常数目N+1,
Q:为什么要创建线程池?线程池的作用?
A:线程池的作用:限制系统中执行线程的数量.
创建线程池可以减少创建线程,销毁线程次数,每个线程都可以多次重复使用,执行多个任务.可以合适的设置线程数量,减轻系统负担,防止内存使用过度,系统崩溃.
Q:线程池的创建,生命周期
A:线程池的顶级接口是Executor,在java.util.concurrent包下,但executor并不是一个线程池,只是一个线程池的执行工具,真正的接口是executorService.其中比较重要的几个类是:
ExecutorService:真正的线程池接口
ScheduledExecutorService:和Timer/TimerTask类似,执行重复周期任务
ThreadPoolExecutor:ExecutorService的底层实现
ScheduledThreadPoolExecutor:继承ThreadPoolExecutor和ScheduledExecutorService接口实现,周期性任务调度的实现.
运行状态:
1.Running:可接受新任务,也可以处理阻塞队列里的任务
2.Shutdown:关闭状态,不再接受新任务,但是可以处理阻塞队列里的任务.当线程池处于Running状态时,调用shutdown方法,变成该状态.
3.Stop:不接收新任务,不处理阻塞队列里的任务,正在进行的任务中断.处于Running状态的线程池调用ShutdownNow方法,生成该状态.
4.Tidying:该状态表示所有的线程都已经终止了,当前没有有效的线程,将要调用terminated方法
5.Terminated:终止状态,线程池调用完terminated后所处的状态.
线程池创建的种类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExecutorTest {
public static void main(String[] args) {
// SingleThreadPoolTest singleThreadPoolTest = new SingleThreadPoolTest();
// singleThreadPoolTest.singleThreadPoolTest();
// TestFixedThreadPool testFixedThreadPool = new TestFixedThreadPool();
// testFixedThreadPool.testFixedThreadPool();
// CashedThreadPoolTest test = new CashedThreadPoolTest();
// test.test();
ScheduleThreadPoolTest test = new ScheduleThreadPoolTest();
test.testScheduleThreadPool();
}
}
/**
* @author dai
* 创建一个单线程池,这个线程池只有一个线程在工作,当这个线程遇到异常时,会重新创建一个线程继续进行任务
* 此线程的执行顺序是按照任务提交的顺序执行
*/
class SingleThreadPoolTest {
ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();
public void singleThreadPoolTest(){
for(int i = 0; i < 10; i ++) {
final int index = i;
singleExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始处理线程" + Thread.currentThread().getName()+"----"+index);
Thread.sleep(index * 1000);
System.out.println("线程处理结束" + Thread.currentThread().getId()+"----"+index);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
/**
* @author dai
* 创建固定大小的线程,每开始一个任务便创建一个线程,直到达到线程池的最大值
* 当一个线程发生异常后,线程池便会重新创建一个新的线程加入线程池
*/
class TestFixedThreadPool{
ExecutorService fixedExecutorService = Executors.newFixedThreadPool(3);
public void testFixedThreadPool() {
for(int i = 0;i < 10; i++) {
final int index = i;
fixedExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始处理线程" + Thread.currentThread().getName() + index);
Thread.sleep(index * 1000);
System.out.println("线程处理结束" + Thread.currentThread().getId() + "----" + index);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
/**
* @author dai
* 缓存线程池,此线程池会回收超过执行任务所需线程大小的线程,但是当任务执行量增加时,会再次智能创建线程来执行任务
* 此线程池的不对大小做限制,大小完全依赖JVM能够操作的最大数量
*/
class CashedThreadPoolTest{
ExecutorService cashedTExecutorService = Executors.newCachedThreadPool();
public void test() {
for(int i = 0; i < 10; i++) {
final int index = i;
cashedTExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始处理线程" + Thread.currentThread().getName() + "----" + index);
Thread.sleep(index * 1000);
System.out.println("线程处理结束" + Thread.currentThread().getId() + "----" + index);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
/**
* @author dai
* 创建大小无限的线程池,支持定时和周期性任务执行任务
*/
class ScheduleThreadPoolTest {
ScheduledExecutorService scheduleThreadService = Executors.newScheduledThreadPool(5);
public void testScheduleThreadPool() {
for(int i = 0; i < 10; i ++) {
final int index = i;
// scheduleThreadService.schedule(new Runnable() {
//
// @Override
// public void run() {
// System.out.println(System.currentTimeMillis() / 1000 + "======");
// try {
// System.out.println("开始处理线程" + Thread.currentThread().getName() + "----" + index);
// Thread.sleep(index * 1000);
// System.out.println("线程处理结束" + Thread.currentThread().getId() + "----" + index);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }, 3, TimeUnit.SECONDS);
// // 循环任务,按照上一次任务的发起时间计算下一次任务的开始时间
// scheduleThreadService.scheduleAtFixedRate(new Runnable() {
//
// @Override
// public void run() {
// System.out.println(System.currentTimeMillis() / 1000 + "********");
// try {
// System.out.println("开始处理线程" + Thread.currentThread().getName() + "----" + index);
// Thread.sleep(index * 1000);
// System.out.println("线程处理结束" + Thread.currentThread().getId() + "----" + index);
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
// }, 0, 3, TimeUnit.SECONDS);
//循环任务,以上一次任务的结束时间计算下一次任务的开始时间
scheduleThreadService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println(System.currentTimeMillis() / 1000 + "@@@@@@");
try {
System.out.println("开始处理线程" + Thread.currentThread().getName() + "----" + index);
Thread.sleep(index * 1000);
System.out.println("线程处理结束" + Thread.currentThread().getId() + "----" + index);
} catch (Exception e) {
e.printStackTrace();
}
}
}, 0, 30, TimeUnit.SECONDS);
}
}
}
创建线程池的参数有哪些呢?
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class CustomThreadPoolExecutor {
// private ThreadPoolExecutor pool = null;
// /**
// * 线程池初始化方法
// *
// * corePoolSize 核心线程池大小----10
// * maximumPoolSize 最大线程池大小----30
// * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit
// * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES
// * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列
// * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂
// * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,
// * 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),
// * 任务会交给RejectedExecutionHandler来处理
// */
// public void init() {
// pool = new ThreadPoolExecutor(
// 10,
// 30,
// 30,
// TimeUnit.MINUTES,
// new ArrayBlockingQueue<Runnable>(10),
// new CustomThreadFactory(),
// new CustomRejectedExecutionHandler());
// }
//
// public void destory() {
// if(pool != null) {
// pool.shutdownNow();
// }
// }
//
// public ExecutorService getCustomThreadPoolExecutor() {
// return this.pool;
// }
//
// private class CustomThreadFactory implements ThreadFactory {
//
// private AtomicInteger count = new AtomicInteger(0);
//
// @Override
// public Thread newThread(Runnable r) {
// Thread t = new Thread(r);
// String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);
// System.out.println(threadName);
// t.setName(threadName);
// return t;
// }
// }
//
// private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
//
// @Override
// public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// // 记录异常
// // 报警处理等
// System.out.println("error.............");
// }
// }
//
// // 测试构造的线程池
// public static void main(String[] args) {
// CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();
// // 1.初始化
// exec.init();
//
// ExecutorService pool = exec.getCustomThreadPoolExecutor();
// for(int i=1; i<100; i++) {
// System.out.println("提交第" + i + "个任务!");
// pool.execute(new Runnable() {
// @Override
// public void run() {
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("running=====");
// }
// });
// }
//
// // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了
// // exec.destory();
//
// try {
// Thread.sleep(10000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
private ThreadPoolExecutor pool = null;
//核心线程池大小
private static int COREPOOLSIZE = 1;
//最大线程池大小
private static int MAXIMUMPOOLSIZE = 3;
/**
* 线程池初始化方法
*
* corePoolSize 核心线程池大小----1
* maximumPoolSize 最大线程池大小----3
* keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit
* TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES
* workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(5)====5容量的阻塞队列
* threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂
* rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,
* 即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),
* 任务会交给RejectedExecutionHandler来处理
*/
public void init() {
pool = new ThreadPoolExecutor(
COREPOOLSIZE,
MAXIMUMPOOLSIZE,
30,
TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(5),
new CustomThreadFactory(),
new CustomRejectedExecutionHandler());
}
public void destory() {
if(pool != null) {
pool.shutdownNow();
}
}
public ExecutorService getCustomThreadPoolExecutor() {
return this.pool;
}
private class CustomThreadFactory implements ThreadFactory {
private AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);
System.out.println(threadName);
t.setName(threadName);
return t;
}
}
private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// 核心改造点,由blockingqueue的offer改成put阻塞方法
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 测试构造的线程池
public static void main(String[] args) {
CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();
// 1.初始化
exec.init();
ExecutorService pool = exec.getCustomThreadPoolExecutor();
for(int i=1; i<100; i++) {
System.out.println("提交第" + i + "个任务!");
pool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(">>>task is running=====");
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了
// exec.destory();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void execute(Runnable runnable) {
//任务为空时抛出异常
if(runnable == null) throw new NullPointerException();
}
}
线程池运行的4个阶段:
1.当前线程数量不足核心线程数时,则直接创建新的线程来执行当前提交的任务;
2.当前线程数量等于核心线程数时,并且阻塞队列未满,如果此时存在工作线程的话,哪呢会由工作线程来处理阻塞队列中的任务,如果没有工作线程数量的话,那么会创建一哥工作线程出来;
3.当前线程数量等于核心线程数时,此时阻塞队列已经满了,那么会直接创建新的工作线程来处理阻塞队列中的任务;
4.当前线程数量是等于最大线程池大小时,并且此时阻塞队列也满了的话,那么会触发拒绝机制,具体决绝策略采用的是什么要看我们创建ThreadPoolExecutor的时候传入的RejectExecutionHandler参数了.
最后就是线程池是怎样被关闭的呢?
涉及到线程池的关闭,需要用到两个方法,shutdown和shutdownNow,他们都是位于ThreadPoolExecutor里面的,对于shutdown的话,他会将线程池状态切换成Shutdown,此时是不会影响对阻塞队列中任务执行的,但是会拒绝执行新加进来的任务,同时会回收闲置的Worker;而shutdownNow方法会将线程池状态切换成Stop,此时既不会再去处理阻塞队列里面的任务,也不会去处理新加进来的任务,同时会回收所有Worker.