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

简介: [一]线程池存在的价值: ==>多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。    ==>假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

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

==>多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   
==>假设一个服务器完成一项任务所需时间为: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 } 
View Code

 

相关文章
|
1月前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
112 38
|
23天前
|
Java
.如何根据 CPU 核心数设计线程池线程数量
IO 密集型:核心数*2 计算密集型: 核心数+1 为什么加 1?即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保 CPU 的时钟周期不会被浪费。
23 4
|
1月前
|
Java
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
76 2
|
1月前
|
Prometheus 监控 Cloud Native
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
84 4
|
1月前
|
Prometheus 监控 Cloud Native
在 Java 中,如何使用线程池监控以及动态调整线程池?
【10月更文挑战第22天】线程池的监控和动态调整是一项重要的任务,需要我们结合具体的应用场景和需求,选择合适的方法和策略,以确保线程池始终处于最优状态,提高系统的性能和稳定性。
230 2
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
26 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
22 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
35 2
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
41 1
|
27天前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
58 0