最近在学习线程相关的知识,而后瓜熟蒂落少不了学习线程池,刚开始在没有深刻的学习以前,感受线程池是很神秘的东西,并且彻底想不到怎么才能实现一个本身的线程池,而后还能保证它的可用性,而后就一直琢磨,琢磨了一周才很少,也是网上各类查资料,终于明白了线程池的原理,也本身手写一个线程池,来加深印象,那么本文咱们就来聊一聊关于线程池的知识,但愿更多的猿友能看到,今后对线程池有一个清晰直观的认识。java
1.什么是线程池数据库
线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样能够避免反复建立线程对象所带来的性能开销,节省了系统的资源。设计模式
2.使用线程池的好处数组
合理的使用线程池能够重复利用已建立的线程,这样就能够减小在建立线程和销毁线程上花费的时间和资源。而且,线程池在某些状况下还能动态的调整工做线程的数量,以平衡资源消耗和工做效率。同时线程池还提供了对池中工做线程进行统一的管理的相关方法。这样就至关于咱们一次建立,就能够屡次使用,大量的节省了系统频繁的建立和销毁线程所须要的资源。ide
3.线程池的主要组件性能
一个线程池包括如下四个基本组成部分:
(1)、线程池管理器(ThreadPool):用于建立并管理线程池,包括 建立线程池,销毁线程池,添加新任务;
(2)、工做线程(WorkThread):线程池中线程,在没有任务时处于等待状态,能够循环的执行任务;
(3)、任务接口(Task):每一个任务必须实现的接口,以供工做线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工做,任务的执行状态等;
(4)、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。学习
4.JDK中线程池经常使用类UML类关系图测试
咱们知道了线程池的原理以及主要组件以后,就让咱们来手动实现一个本身的线程池,以加深理解和深刻学习。this
1.线程池接口类atom
package com.hafiz.proxy.threadPool; import java.util.List; /** * Desc:线程池接口类 * Created by hafiz.zhang on 2017/9/19. */ public interface ThreadPool { // 执行单个线程任务 void execute(Runnable task); // 执行多个任务 void execute(Runnable[] tasks); // 执行多个任务 void execute(List<Runnable> tasks); // 返回已经执行的任务个数 int getExecuteTaskNumber(); // 返回等待被处理的任务个数,队列的长度 int getWaitTaskNumber(); // 返回正在工做的线程的个数 int getWorkThreadNumber(); // 关闭线程池 void destroy(); }
2.线程池实现类ThreadPoolManager.java
package com.hafiz.proxy.threadPool; import java.util.Arrays; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; /** * Desc:线程池实现类 * Created by hafiz.zhang on 2017/9/19. */ 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; } } }
其中该类中包含内部类WorkThread,它用来包装真正的线程类,给每个线程一个是否可用的标志,该线程工做室同步的从taskQueue中取出要执行的任务进行调用run方法来执行任务。
这个类中的getThreadPool方法中咱们还使用到了懒汉式来实现单例,单例模式也是Java经常使用设计模式之一。
注意该类中的destroy方法的实现:咱们是一直等到队列中的全部的任务执行完毕,才真正的销毁线程池,销毁的过程当中不要忘记将每个线程对象置为null,而且清空任务队列,这样更利于java的垃圾回收。
3.自定义任务类Task.java
package com.hafiz.proxy.threadPool; /** * Desc:自定义任务类 * Created by hafiz.zhang on 2017/9/21. */ public class Task implements Runnable { private static volatile Integer i = 1; @Override public void run() { // 执行任务 synchronized (i) { System.out.println("当前处理的线程是:" + Thread.currentThread().getName() + ",执行任务:" + (i++) + "完成"); } } }
4.线程池测试类
package com.hafiz.proxy.threadPool; import java.util.ArrayList; import java.util.List; /** * Desc:线程池测试类 * Created by hafiz.zhang on 2017/9/20. */ 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); } }
5.测试结果:(为了篇幅,只建立10个任务运行)
经过本文,咱们弄明白线程池究竟是怎么工做,学习知识的过程当中,咱们就是要知其然知其因此然。这样咱们才能更好地驾驭它,才能更好地去理解和使用,也能更好地帮助咱们举一反三,后面有机会咱们接着来讲数据库链接池的原理及手写实现。