线程池
线程池的目的
什么是线程池:
线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
线程池的好处:
1、能够在某些情况下动态的调整工作线程的数量
2、可以大量节省系统频繁的创建和销毁线程所需要的资源
3、提高响应速度
线程池的组成:
1、线程池管理器(ThreadPoolManager):
用于创建并管理线程池 包括创建线程,销毁线程池,添加任务
2、工作线程(WorkThread):
线程池中线程,在没有任务时处于等待状态,可以循环的执行任务
3、任务接口(Task):
每个任务必须实现的接口,以供工作线程调度任务的执行。它规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。
如何创建一个线程池?
Java中提供了创建线程程池的一个类:Executor
创建时,一般使用它的子类即:ThreadPoolExector
线程池中的corePoolSize就是线程池中的核心线程数量,这几个核心线程,只是在没有用的时候,也不会被回收,maximumPoolSize就是线程池中可以容纳的最大线程的数量,而keepAliveTime,就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间,而util,就是计算这个时间的一个单位,workQueue,就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。threadFactory,就是创建线程的线程工厂,最后一个handler,是一种拒绝策略,我们可以在任务满了之后,拒绝执行某些任务。
任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。
handler的拒绝策略:
有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满这是默认使用的拒绝策略
第二种DisCardPolicy:不执行新任务,也不抛出异常
第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
第四种CallerRunsPolicy:直接调用execute来执行当前任务
线程池的种类
四种常见的线程池:
CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于量大但小而轻的任务。
SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
SingleThreadPool:只有一条线程来执行任务一个线程消亡会有一个新的线程代替,适用于有顺序的任务的应用场景适用于任务单一要求顺序的任务。
FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程适用于负载重
线程池的基本实现:
-
线程池接口类 ThreadPool
``
import java.util.List; /** * Desc:线程池接口类 */ public interface ThreadPool { // 执行单个线程任务 void execute(Runnable task); // 执行多个任务 void execute(Runnable[] tasks); // 执行多个任务 void execute(List<Runnable> tasks); // 返回已经执行的任务个数 int getExecuteTaskNumber(); // 返回等待被处理的任务个数,队列的长度 int getWaitTaskNumber(); // 返回正在工作的线程的个数 int getWorkThreadNumber(); // 关闭线程池 void destroy(); }
-
线程池实现类ThreadPoolManager.java
``
import java.util.Arrays; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; /** * Desc:线程池实现类 */ public class ThreadPoolManager implements ThreadPool { // 线程池中默认线程的个数为5 private static Integer workerNum = 5; // 工作线程数组 WorkThread[] workThreads; // 正在执行的线程任务数量 private static volatile Integer executeTaskNumber = 0; // 任务队列, 作为一个缓冲 private Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<>(); // 单例模式 private static ThreadPoolManager threadPool; private AtomicLong threadNum = new AtomicLong(); private ThreadPoolManager() { this(ThreadPoolManager.workerNum); } private ThreadPoolManager(int workerNum) { if (workerNum > 0) { ThreadPoolManager.workerNum = workerNum; } workThreads = new WorkThread[ThreadPoolManager.workerNum]; for (int i = 0; i < ThreadPoolManager.workerNum; i++) { workThreads[i] = new WorkThread(); Thread thread = new Thread(workThreads[i], "ThreadPool-worker-" + threadNum.incrementAndGet()); thread.start(); System.out.println("初始化线程总数:" + (i+1) + ",当前线程名称是:ThreadPool-worker-" + threadNum); } } public static ThreadPool getThreadPool() { return getThreadPool(workerNum); } public static ThreadPool getThreadPool(int workerNum) { if (workerNum > 0) { ThreadPoolManager.workerNum = workerNum; } if (threadPool == null) { threadPool = new ThreadPoolManager(ThreadPoolManager.workerNum); } return threadPool; } @Override public void execute(Runnable task) { synchronized (taskQueue) { taskQueue.add(task); taskQueue.notifyAll(); } } @Override public void execute(Runnable[] tasks) { execute(Arrays.asList(tasks)); } @Override public void execute(List<Runnable> tasks) { synchronized (taskQueue) { for (Runnable task : tasks) { taskQueue.add(task); } taskQueue.notifyAll(); } } @Override public String toString() { return "ThreadPoolManager{" + "当前的工作线程数量=" + getWorkThreadNumber() + ", 已完成的任务数=" + getExecuteTaskNumber() + ", 等待任务数=" + getWaitTaskNumber() + '}'; } @Override public int getExecuteTaskNumber() { return executeTaskNumber; } @Override public int getWaitTaskNumber() { return taskQueue.size(); } @Override public int getWorkThreadNumber() { return workerNum; } @Override public void destroy() { while (!taskQueue.isEmpty()) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < workThreads.length; i++) { workThreads[i].shutdown(); workThreads[i] = null; } threadPool = null; taskQueue.clear(); } private class WorkThread implements Runnable { // 线程是否可用 private boolean isRunning = true; @Override public void run() { Runnable r = null; while (isRunning) { // 队列同步机制,加锁 synchronized (taskQueue) { while (isRunning && taskQueue.isEmpty()) { try { taskQueue.wait(20); } catch (InterruptedException e) { e.printStackTrace(); } } if (!taskQueue.isEmpty()) { r = taskQueue.poll(); } } if (r != null) { r.run(); } executeTaskNumber++ ; r = null; } } public void shutdown() { isRunning = false; } } }
-
自定义任务类Task.java
``
/** * Desc:自定义任务类 */ public class Task implements Runnable { private static volatile Integer i = 1; @Override public void run() { // 执行任务 synchronized (i) { System.out.println("当前处理的线程是:" + Thread.currentThread().getName() + ",执行任务:" + (i++) + "完成"); } } }
-
线程池测试类
``
import java.util.ArrayList; import java.util.List; /** * Desc:线程池测试类 */ public class ThreadPoolTest { public static void main(String[] args) { ThreadPool t = ThreadPoolManager.getThreadPool(6); List<Runnable> tasks = new ArrayList<>(); for (int i = 0; i < 100; i++) { tasks.add(new Task()); } System.out.println(t); t.execute(tasks); // 所有的线程执行完成才destroy t.destroy(); System.out.println(t); } }
核心参数的意义
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize, //可以容纳的最大线程的数量
long keepAliveTime, //非核心线程可以保留的空闲时间
TimeUnit unit, //计算空闲时间的单位
BlockingQueue workQueue, //等待队列
ThreadFactory threadFactory, //创建线程的线程工厂
RejectedExecutionHandler handler//拒绝策略,任务满了之后拒绝执行某些任务
)
核心方法讲解
AbstractExecutorService抽象类的基本属性
AbstractExecutorService是个抽象类主要是对ExecutorService接口方法的一些实现。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//这个状态位是来记录workerCount和runState的值,高三位是运行状态,低29位是workerCount的值
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; //容量 2^29 -1
// 表示线程池可以接受新的任务,并且处理阻塞队列当中的任务
private static final int RUNNING = -1 << COUNT_BITS;
// 不接受新的任务,但是会去处理阻塞队列当中的任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 不接受新的任务,不处理队列当中的任务,中止正在运行中的任务
private static final int STOP = 1 << COUNT_BITS;
// 所有的任务都中止了,workCount变为0,并且会去执行terminated方法
private static final int TIDYING = 2 << COUNT_BITS;
// 在TIDYING状态的基础上,执行完了terminated方法
private static final int TERMINATED = 3 << COUNT_BITS;
private final BlockingQueue<Runnable> workQueue; // 阻塞队列
private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet<Worker> workers = new HashSet<Worker>(); //存放执行的任务
private final Condition termination = mainLock.newCondition(); //终止条件
//线程池执行过得最大线程数
private int largestPoolSize;
//已经完成的线程数
private long completedTaskCount;
//创建线程的线程工厂
private