多线程之:模拟实现线程池的工作原理

[一]线程池存在的价值:

==>多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   
==>假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
==>如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

[二]合理利用线程池能够带来三个好处。

* 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
 * 第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
 * 第三:提高线程的可管理

[三]一个线程池的组成部分

(1)线程池管理器

=>其中线程池管理器的作用是创建、销毁并管理线程池,将工作线程放入线程池中;

=>线程池管理器至少有下列功能:创建线程池,销毁线程池,添加新任务。

(2)工作线程

=>工作线程是一个可以循环执行任务的线程,在没有任务是进行等待;
=>工作线程是一个可以循环执行任务的线程,在没有任务时将等待。

(3)任务列队

=>任务列队的作用是提供一种缓冲机制,将没有处理的任务放在任务列队中;

(4)任务接口等部分。

=>任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。
=>任务接口是为所有任务提供统一的接口,以便工作线程处理。任务接口主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等。

[四]模拟实现一个线程池的原理

  1 package mine.util.thread;
  2
  3 import java.util.LinkedList;
  4 import java.util.List;
  5
  6 /**
  7  * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息
  8  */
  9 public final class ThreadPool {
 10     // 线程池中默认线程的个数为5
 11     private static int worker_num = 5;
 12     // 工作线程
 13     private WorkThread[] workThrads;
 14     // 未处理的任务
 15     private static volatile int finished_task = 0;
 16     // 任务队列,作为一个缓冲,List线程不安全
 17     private List<Runnable> taskQueue = new LinkedList<Runnable>();
 18     private static ThreadPool threadPool;
 19
 20     // 创建具有默认线程个数的线程池
 21     private ThreadPool() {
 22         this(5);
 23     }
 24
 25     // 创建线程池,worker_num为线程池中工作线程的个数
 26     private ThreadPool(int worker_num) {
 27         ThreadPool.worker_num = worker_num;
 28         workThrads = new WorkThread[worker_num];
 29         for (int i = 0; i < worker_num; i++) {
 30             workThrads[i] = new WorkThread();
 31             workThrads[i].start();// 开启线程池中的线程
 32         }
 33     }
 34
 35     // 单态模式,获得一个默认线程个数的线程池
 36     public static ThreadPool getThreadPool() {
 37         return getThreadPool(ThreadPool.worker_num);
 38     }
 39
 40     // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
 41     // worker_num<=0创建默认的工作线程个数
 42     public static ThreadPool getThreadPool(int worker_num1) {
 43         if (worker_num1 <= 0)
 44             worker_num1 = ThreadPool.worker_num;
 45         if (threadPool == null)
 46             threadPool = new ThreadPool(worker_num1);
 47         return threadPool;
 48     }
 49
 50     // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
 51     public void execute(Runnable task) {
 52         synchronized (taskQueue) {
 53             taskQueue.add(task);
 54             taskQueue.notify();
 55         }
 56     }
 57
 58     // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
 59     public void execute(Runnable[] task) {
 60         synchronized (taskQueue) {
 61             for (Runnable t : task)
 62                 taskQueue.add(t);
 63             taskQueue.notify();
 64         }
 65     }
 66
 67     // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
 68     public void execute(List<Runnable> task) {
 69         synchronized (taskQueue) {
 70             for (Runnable t : task)
 71                 taskQueue.add(t);
 72             taskQueue.notify();
 73         }
 74     }
 75
 76     // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
 77     public void destroy() {
 78         while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
 79             try {
 80                 Thread.sleep(10);
 81             } catch (InterruptedException e) {
 82                 e.printStackTrace();
 83             }
 84         }
 85         // 工作线程停止工作,且置为null
 86         for (int i = 0; i < worker_num; i++) {
 87             workThrads[i].stopWorker();
 88             workThrads[i] = null;
 89         }
 90         threadPool=null;
 91         taskQueue.clear();// 清空任务队列
 92     }
 93
 94     // 返回工作线程的个数
 95     public int getWorkThreadNumber() {
 96         return worker_num;
 97     }
 98
 99     // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成
100     public int getFinishedTasknumber() {
101         return finished_task;
102     }
103
104     // 返回任务队列的长度,即还没处理的任务个数
105     public int getWaitTasknumber() {
106         return taskQueue.size();
107     }
108
109     // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数
110     @Override
111     public String toString() {
112         return "WorkThread number:" + worker_num + "  finished task number:"
113                 + finished_task + "  wait task number:" + getWaitTasknumber();
114     }
115
116     /**
117      * 内部类,工作线程
118      */
119     private class WorkThread extends Thread {
120         // 该工作线程是否有效,用于结束该工作线程
121         private boolean isRunning = true;
122
123         /*
124          * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
125          */
126         @Override
127         public void run() {
128             Runnable r = null;
129             while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了
130                 synchronized (taskQueue) {
131                     while (isRunning && taskQueue.isEmpty()) {// 队列为空
132                         try {
133                             taskQueue.wait(20);
134                         } catch (InterruptedException e) {
135                             e.printStackTrace();
136                         }
137                     }
138                     if (!taskQueue.isEmpty())
139                         r = taskQueue.remove(0);// 取出任务
140                 }
141                 if (r != null) {
142                     r.run();// 执行任务
143                 }
144                 finished_task++;
145                 r = null;
146             }
147         }
148
149         // 停止工作,让该线程自然执行完run方法,自然结束
150         public void stopWorker() {
151             isRunning = false;
152         }
153     }
154 } 

时间: 2024-08-28 01:33:32

多线程之:模拟实现线程池的工作原理的相关文章

线程池的工作原理及使用示例

欢迎探讨,如有错误敬请指正 如需转载,请注明出处  http://www.cnblogs.com/nullzx/ 1. 为什么要使用线程池? 我们现在考虑最简单的服务器工作模型:服务器每当接收到一个客户端请求时就创建一个线程为其服务.这种模式理论上可以工作的很好,但实际上会存在一些缺陷,服务器应用程序中经常出现的情况是单个客户端请求处理的任务很简单但客户端的数目却是巨大的,因此服务器在创建和销毁线程所花费的时间和系统资源可能比处理客户端请求处理的任务花费的时间和资源更多. 线程池技术就是为了解决

java多线程之Executor框架线程池详细介绍与ThreadPoolExecutor

Executor框架简介 Executor框架的结构 Executor框架主要由3大部分组成: 任务: 包括被执行的任务需要实现的接口:Runable 接口.Callable接口: 任务的执行: 包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口.Executor框架有两个关键类实现了ExecutorService接口:ThreadPoolExecutor 和 ScheduledThreadPoolExecutor.ForkJoinPool

线程池的工作原理与源码解读

随着cpu核数越来越多,不可避免的利用多线程技术以充分利用其计算能力.所以,多线程技术是服务端开发人员必须掌握的技术. 线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以就引入了线程池技术,避免频繁的线程创建和销毁. 在Java用有一个Executors工具类,可以为我们创建一个线程池,其本质就是new了一个ThreadPoolExecutor对象.线程池几乎也是面试必考问题.本节结合源代码,说说ThreadExecutor的工作原理 一.线程池创建 先看一下ThreadPoolExec

线程池ThreadPoolExecutor工作原理

前言 工作原理 如果使用过线程池,细心的同学肯定会注意到,new一个线程池,但是如果不往里面提交任何任务的话,main方法执行完之后程序会退出,但是如果向线程池中提交了任务的话,main方法执行完毕之后程序是不会自动退出的,是什么原理,或者说是什么原因导致任务提交到线程池之后任务执行完程序无法自动退出的呢?下面就让我们趴开线程池的源码,一探究竟. 我们直接从ThreadPoolExecutor的execute方法开始说起.线程提交到ThreadPoolExecutor执行分为三种情况,具体如下:

线程池的工作原理阅读总结

线程池使用了一种池化技术,和很多其他池化技术一样,都是为了更高效的利用资源,例如链接池,内存池等等 线程池一共有五种状态,运行状态,待关闭状态,停止状态,整理状态,终止状态,一个线程池的核心参数有很多,每个参数都有着特殊的作用,各个参数聚合在一起 后将完成整个线程池的完整工作,每一个工作线程中都维持着一个Thread,线程池的重点之一就是控制线程资源合理高效的使用,所以必须控制工作线程的个数,所以要保存当前线程中的工作线程个数. 线程池设计了两个变量来协作,分别是核心线程数和最大线程数,核心线程

Java 线程池概念、原理、简单实现

线程池的思想概述 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结東了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间.那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?Java中可以通过线程池来达到这样的效果.下面们就来详细讲解一下Java的线程池. 线程池概念 线程池其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省

线程池的实现原理

1.线程池简介:    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.        假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间. 如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能.                一个线程池包括以下四个基本组成部分:                1.线程池管理器(ThreadPool):用于创建并管理线程池,包

21.线程池ThreadPoolExecutor实现原理

1. 为什么要使用线程池 在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题.因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处: 降低资源消耗.通过复用已存在的线程和降低线程关闭的次数来尽可能降低系统性能损耗: 提升系统响应速度.通过复用线程,省去创建线程的过程,因此整体上提升了系统的响应速度: 提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,因此,需要使用线程池来管理线程. 2. 线程池的

Java 线程池ExecutorService运行原理 和FutureTask 的使用

一.线程池ExecutorService运行原理 ThreadPoolExecutor中有corePoolSize(核心线程)和maximumPoolSize(工作线程),默认核心线程和工作线程数量一致.1.当线ExecutorService线程池,使用submit,或者execute时2.先判断运行中的线程是否大于corePoolSize(核心线程)数量3.如果大于corePoolSize(核心线程)且maximumPoolSize(工作线程)未满则把该线程存着到工作线程等待.4.如果大于co