1.线程池的作用
1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3. 提高线程的可管理性。
2.线程池原理
分析:我们如何理解这幅图呢,以及我们可以简单对它们进行简单的模仿?
1. 核心线程池就像相当于我们互联网公司的核心成员。
2. 当任务来的时候,核心线程池进行消费,当任务比较多的时候,由产品经理把任务统计起来(就是任务队列),如果产品经理发现任务多的已经统计不过来,说明任务队列已经满了。
3. 在任务队列里面任务太多的时候,公司就会进行招聘一些外包人员,这时的线程就是核心线程以外的线程,并且会把它们放到一个线程池中,让这些外包也来完成产生的任务,但是这时候外包人员也不能处理产生的任务
4.就会产生一种策略,其实这些策略就是异常处理,在jdk提供了四种处理异常的策略
异常策略:
- CallerRunsPolicy:只要线程池没关闭,就直接用调用者所在线程来运行任务
- AbortPolicy:直接抛出 RejectedExecutionException 异常
- DiscardPolicy:悄悄把任务放生,不做了
- DiscardOldestPolicy:把队列里待最久的那个任务扔了,然后再调用 execute() 试试看能行不
3. jdk提供四种线程池
ThreadPoolExecutor:
分析:我们可以看到jdk里面提供的四种线程池里面最后都是调用threadpoolexecutor这个类,但是这个类里面有7个参数,分别
corePoolSize:核心线程大小(及互联网公司的核心成员)
maximumPoolSize:最大线程池的大小(外包人员)
keepAliveTime:除过核心线程池外,其他线程的存活时间。(及外包人员的存活时间)
unit:创建线程的存活时间
workQueue:任务队列,在jdk里面提供四种任务队列
- ArrayBlockingQueue:基于数组、有界,按 FIFO(先进先出)原则对元素进行排序
- LinkedBlockingQueue:基于链表,按FIFO (先进先出) 排序元素
吞吐量通常要高于 ArrayBlockingQueue
Executors.newFixedThreadPool() 使用了这个队列
- SynchronousQueue:不存储元素的阻塞队列
每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
吞吐量通常要高于 LinkedBlockingQueue
Executors.newCachedThreadPool使用了这个队列
- PriorityBlockingQueue:具有优先级的、无限阻塞队列
threadFactory:线程工厂,对线程进行管理
策略模式:出现异常时,使用的策略。
1. newFixedThreadPool:
分析:keepAliveTime为0,说明只有核心线程池,产生的核心线程池以外的线程,它们的存活时间将变为0,那么在极端情况下,如果任务比较多的话,会很快使任务队列已满,可以用于负载比较重的服务器。
2. newSingleThreadExecutor:
分析:是上面newFixThreadPool的一个特例,里面核心线程只有一个,没有其他多余的线程, 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。
3. newCachedThreadPool:
分析:可以看出corePoolSize的大小为0,可以说全是外包,极端情况下会创建过多的线程,耗尽 CPU 和内存资源。
CachedThreadPool
用于并发执行大量短期的小任务,或者是负载较轻的服务器。
4. newScheduledThreadPool:
分析:ScheduledThreadPoolExecutor
用于需要多个后台线程执行周期任务,同时需要限制线程数量的场景。
4.简单模仿线程池
1. 首先一定这个线程池的行为规范有哪些
- 执行线程的接口
- 得到当前任务队列(这个任务队列就是池子,让生产者生产任务,让消费者任务)里面的任务数量
- 得到当前任务队列里面已经消费的任务数量
- 得到当前的工作线程数量
2. 定义ThreadManagePool这个类
- 首先需要实现ThreadPool的行为规范
- 需要定义消费者类,这个类主要是消费任务,但是必须把它和生产者结合起来,它必须只要什么时候需要消费,在这里使用一个链表,把两者结合起来,消费者必须每一次检查链表是不是空,如果是空的,就进行等待,直到链表不为空,进行消费。
- 销毁线程,首先要检查任务队列里面的任务是否消费完毕,如果没有完毕进行等待处理,如果消费完毕,关闭每一个消费者,在关闭线程池。
public class ThreadManagePool implements ThreadPool {
//默认工作线程个数
private static int workerNum = 5;
//工作线程数量
public WorkThread[] workThreads;
//执行任务数量
private static volatile int executeTaskNumber = 0;
private static ThreadManagePool threadManagePool;
private List<Runnable> taskQueue = new LinkedList<Runnable>();
private ThreadManagePool(){
this(workerNum);
}
private ThreadManagePool(int workerNum){
if(workerNum > 0) {
ThreadManagePool.workerNum = workerNum;
}
//工作线程的初始化
workThreads = new WorkThread[workerNum];
for(int i = 0;i<ThreadManagePool.workerNum;i++) {
workThreads[i] = new WorkThread();
Thread thread = new Thread(workThreads[i]);
System.out.println("初始化线程总数" + (i + 1) + "------当前线程名称是:" + thread.getName());
thread.start();
}
}
public static ThreadPool getThreadPool(){
return getTheadPool(ThreadManagePool.workerNum);
}
public static ThreadPool getTheadPool(int workNum){
if(workNum <= 0) {
workNum = ThreadManagePool.workerNum;
}
if(threadManagePool == null) {
threadManagePool = new ThreadManagePool(workNum);
}
return threadManagePool;
}
/**
* 线程池销毁
*/
@Override
public void destory() {
while (!taskQueue.isEmpty()) {
try {
//不断检测任务队列是否全部执行
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < workerNum; i++) {
workThreads[i].stopWorker();
workThreads[i] = null;
}
threadManagePool = null;
taskQueue.clear();
}
@Override
public void execute(Runnable runnable) {
synchronized (taskQueue) {
taskQueue.add(runnable);
//通知 启动的线程
taskQueue.notifyAll();
}
}
@Override
public void execute(List<Runnable> runnables) {
synchronized (taskQueue) {
for (Runnable task : runnables) {
taskQueue.add(task);
}
taskQueue.notifyAll();
}
}
@Override
public void execute(Runnable[] runnables) {
synchronized (taskQueue) {
for (Runnable task : runnables) {
taskQueue.add(task);
}
taskQueue.notifyAll();
}
}
@Override
public int getExecuteTaskCount() {
return executeTaskNumber;
}
@Override
public int getWorkTaskCount() {
return taskQueue.size();
}
@Override
public int getWorkTheadCount() {
return workerNum;
}
@Override
public String toString() {
return "当前工作线程数:" + workerNum +
", 已完成任务数:" + executeTaskNumber +
", 等待任务数量:" + getWorkTaskCount();
}
private class WorkThread extends Thread{
//该工作线程是否有效 用于结束该工作线程
private boolean isRunning = true;
Runnable r = null;
@Override
public void run() {
super.run();
while(isRunning){
synchronized (taskQueue) {
while(isRunning&&taskQueue.isEmpty()){
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(!taskQueue.isEmpty()) {
r = taskQueue.remove(0);
}
if(r!=null) {
r.run();
}
executeTaskNumber++;
r = null;
}
}
}
//停止工作 让该线程自然执行完run方法 自然结束
public void stopWorker() {
isRunning = false;
}
}
}
public class ThreadTest {
public static void main(String[] args) {
ThreadPool t = ThreadManagePool.getTheadPool(6);
List<Runnable> taskList = new ArrayList<Runnable>();
for (int i = 0; i < 10; i++) {
taskList.add(new task());
}
t.execute(taskList);
System.out.println(t);
t.destory();//所有线程执行完才destory
System.out.println(t);
}
//任务类
public static class task implements Runnable{
private static volatile int i = 1;
@Override
public void run() {
System.out.println("当前处理的线程是:" + Thread.currentThread().getName() + " 执行任务" + (i++) + " 完成");
}
}
}
分析:发现虽然我们初始化许多线程,但是只有一个线程在消费队列里面的任务,主要是因为使用的同一把锁,一次只能让一个线程进入进行消费,是一个串行的过程,有点像jdk里面的singleNewThreadPool这个线程池,还有问题就是我们解耦,通过链表把消费者和生成者联系起来,所以我们应该用一个工具来管理线程,这个类ThreadFactory。
2. 对上述代码进行解耦处理
ThreadFactory类代码:
package com.mec.test;
import java.util.LinkedList;
import java.util.List;
public class ThreadFactory {
//管理线程
private static List<WorkThread> workThreads = new LinkedList<WorkThread>();
//任务队列
private static List<Runnable> workTask = new LinkedList<Runnable>();
private static boolean flag = true;
private volatile static int executeTaskNumber =0;
//使用单例模式
private ThreadFactory(){};
//添加任务
public static void addWorkTask(Runnable runnable){
synchronized (workTask){
workTask.add(runnable);
workTask.notifyAll();
}
}
//添加任务
public static void addWorkTask(List<Runnable> runnables){
synchronized (workTask){
for(Runnable runnable : runnables){
workTask.add(runnable);
}
workTask.notifyAll();
}
}
//添加任务
public static void addWorkTask(Runnable[] runnables){
synchronized (workTask){
for(Runnable runnable : runnables){
workTask.add(runnable);
}
workTask.notifyAll();
}
}
//初始化工作线程
public static void initWorkThread(int initCount){
if(initCount<0){
return;
}
for(int i=0;i<initCount;i++){
workThreads.add(new WorkThread());
Thread thread = new Thread(new WorkThread());
System.out.println("初始化线程总数" + (i + 1) + "------当前线程名称是:" + thread.getName());
thread.start();
}
}
//增加工作线程
public static void addWorkThread(int count){
if(count<0){
return;
}
for(int i=0;i<count;i++){
workThreads.add(new WorkThread());
Thread thread = new Thread(new WorkThread());
System.out.println("初始化线程总数" + (i + 1) + "------当前线程名称是:" + thread.getName());
thread.start();
}
}
//得到线程
public static Runnable getRunnable(){
return workThreads.remove(0);
}
//关闭线程
public static void destory(){
while(!workTask.isEmpty()){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i =0;i<workThreads.size();i++){
WorkThread workThread = workThreads.get(i);
workThread.isRunning = false;
workThread = null;
}
workTask.clear();
}
//得到任务队列里面的个数
public static int getWorkTask(){
return workTask.size();
}
//得到已经执行的任务队列
public static int getExecuteTaskNumber(){
return executeTaskNumber;
}
//得到线程队列里面的个数
public static int getThreadCount(){
return workThreads.size();
}
//工作线程
private static class WorkThread extends Thread{
Runnable runnable = null;
private boolean isRunning = true;
@Override
public void run() {
while (isRunning) {
synchronized (workTask) {
while (workTask.isEmpty()&&isRunning) {
try {
workTask.wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!workTask.isEmpty()) {
runnable = workTask.remove(0);
}
if (runnable != null) {
runnable.run();
}
runnable = null;
executeTaskNumber++;
}
}
}
}
//停止线程
public static void stopThread(){
flag = false;
}
}
ThreadPoolManagers类代码:
package com.mec.test; import java.util.List; public class ThreadPoolManagers implements ThreadPools { private int initCount = 5; private ThreadPoolManagers(){ ThreadFactory.initWorkThread(initCount); } private ThreadPoolManagers(int count){ ThreadFactory.addWorkThread(count); } public static ThreadPools getThreadPool(){ return new ThreadPoolManagers(); } public static ThreadPools getThreadPool(int count){ return new ThreadPoolManagers(count); } @Override public void execute(Runnable task) { ThreadFactory.addWorkTask(task); } @Override public void execute(Runnable[] task) { ThreadFactory.addWorkTask(task); } @Override public void execute(List<Runnable> task) { ThreadFactory.addWorkTask(task); } @Override public int getExecuteTaskNumber() { return ThreadFactory.getExecuteTaskNumber(); } @Override public int getWaitTaskNumber() { return ThreadFactory.getWorkTask(); } @Override public int getWorkThreadNumber() { return ThreadFactory.getThreadCount(); } @Override public void destory() { ThreadFactory.destory(); } @Override public void stop() { ThreadFactory.stopThread(); } @Override public String toString(){ return "当前工作线程数:" + ThreadFactory.getThreadCount() + ", 已完成任务数:" + ThreadFactory.getExecuteTaskNumber() + ", 等待任务数量:" + ThreadFactory.getWorkTask(); } }
ThreadPools类代码:
package com.mec.test;
import java.util.List;
public interface ThreadPools {
void execute(Runnable task);
void execute(Runnable[] task);
void execute(List<Runnable> task);
//返回执行任务的个数
int getExecuteTaskNumber();
//返回任务队列的长度 即还没处理的任务个数
int getWaitTaskNumber();
//返回工作线程的个数
int getWorkThreadNumber();
//关闭线程池
void destory();
//停止线程
void stop();
}
运行类代码:
package com.mec.test;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest1 {
public static void main(String[] args) {
ThreadPools t = ThreadPoolManager.getThreadPool(6);
List<Runnable> taskList = new ArrayList<Runnable>();
for (int i = 0; i < 100; i++) {
taskList.add(new Task());
}
t.execute(taskList);
System.out.println(t);
t.destory();//所有线程执行完才destory
System.out.println(t);
}
//任务类
static class Task implements Runnable {
private static volatile int i = 1;
@Override
public void run() {
System.out.println("当前处理的线程是:" + Thread.currentThread().getName() + " 执行任务" + (i++) + " 完成");
}
}
}
运行结果: