我们通常想要的是同一组固定的工作线程相结合的工作队列,它使用 wait() 和 notify() 来通知等待线程新的工作已经到达了。该工作队列通常被实现成具有相关监视器对象的某种链表。清单 1 显示了简单的合用工作队列的示例。
清单 1. 具有线程池的工作队列
public class WorkQueue
{
private final int nThreads;
private final PoolWorker[] threads;
private final LinkedList queue;
public WorkQueue(int nThreads)
{
this.nThreads = nThreads;
queue = new LinkedList();
threads = new PoolWorker[nThreads];
for (int i=0; i<nThreads; i++) {
threads[i] = new PoolWorker();
threads[i].start();
}
}
public void execute(Runnable r) {
synchronized(queue) {
queue.addLast(r);
queue.notify();
}
}
private class PoolWorker extends Thread {
public void run() {
Runnable r;
while (true) {
synchronized(queue) {
while (queue.isEmpty()) {
try
{
queue.wait();
}
catch (InterruptedException ignored)
{
}
}
r = (Runnable) queue.removeFirst();
}
// If we don't catch RuntimeException,
// the pool could leak threads
try {
r.run();
}
catch (RuntimeException e) {
// You might want to log something here
}
}
}
}
}
使用线程池的风险
虽然线程池是构建多线程应用程序的强大机制,但使用它并不是没有风险的。用线程池构建的应用程序容易遭受任何其它多线程应用程序容易遭受的所有并发风险,诸如同步错误和死锁,它还容易遭受特定于线程池的少数其它风险,诸如与池有关的死锁、资源不足和线程泄漏。
资源不足
线程池的一个优点在于:相对于其它替代调度机制(有些我们已经讨论过)而言,它们通常执行得很好。但只有恰当地调整了线程池大小时才是这样的。线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性能。
如果线程池太大,那么被那些线程消耗的资源可能严重地影响系统性能。在线程之间进行切换将会浪费时间,而且使用超出比您实际需要的线程可能会引起资源匮乏问题,因为池线程正在消耗一些资源,而这些资源可能会被其它任务更有效地利用。除了线程自身所使用的资源以外,服务请求时所做的工作可能需要其它资源,例如 JDBC 连接、套接字或文件。这些也都是有限资源,有太多的并发请求也可能引起失效,例如不能分配 JDBC 连接。
请求过载
仅仅是请求就压垮了服务器,这种情况是可能的。在这种情形下,我们可能不想将每个到来的请求都排队到我们的工作队列,因为排在队列中等待执行的任务可能会消耗太多的系统资源并引起资源缺乏。在这种情形下决定如何做取决于您自己;在某些情况下,您可以简单地抛弃请求,依靠更高级别的协议稍后重试请求,您也可以用一个指出服务器暂时很忙的响应来拒绝请求。
调整池的大小
调整线程池的大小基本上就是避免两类错误:线程太少或线程太多。幸运的是,对于大多数应用程序来说,太多和太少之间的余地相当宽。
请回忆:在应用程序中使用线程有两个主要优点,尽管在等待诸如 I/O 的慢操作,但允许继续进行处理,并且可以利用多处理器。在运行于具有 N 个处理器机器上的计算限制的应用程序中,在线程数目接近 N 时添加额外的线程可能会改善总处理能力,而在线程数目超过 N 时添加额外的线程将不起作用。事实上,太多的线程甚至会降低性能,因为它会导致额外的环境切换开销。
线程池的最佳大小取决于可用处理器的数目以及工作队列中的任务的性质。若在一个具有 N 个处理器的系统上只有一个工作队列,其中全部是计算性质的任务,在线程池具有 N 或 N+1 个线程时一般会获得最大的 CPU 利用率。
对于那些可能需要等待 I/O 完成的任务(例如,从套接字读取 HTTP 请求的任务),需要让池的大小超过可用处理器的数目,因为并不是所有线程都一直在工作。通过使用概要分析,您可以估计某个典型请求的等待时间(WT)与服务时间(ST)之间的比例。如果我们将这一比例称之为 WT/ST,那么对于一个具有 N 个处理器的系统,需要设置大约 N*(1+WT/ST) 个线程来保持处理器得到充分利用。
处理器利用率不是调整线程池大小过程中的唯一考虑事项。随着线程池的增长,您可能会碰到调度程序、可用内存方面的限制,或者其它系统资源方面的限制,例如套接字、打开的文件句柄或数据库连接等的数目。
JDK自带线程池总类介绍介绍:
1、newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
2、newCachedThreadPool创建一个可缓存的线程池。这种类型的线程池特点是:
1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
3、newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的 。
4、newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。(这种线程池原理暂还没完全了解透彻)
总结: 一.FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。
二.CachedThreadPool的特点就是在线程池空闲时,即线程池中没有可运行任务时,它会释放工作线程,从而释放工作线程所占用的资源。但是,但当出现新任务时,又要创建一新的工作线程,又要一定的系统开销。并且,在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。
分享到:
相关推荐
线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池线程池...
### JAVA线程池原理及几种线程池类型的详细介绍 #### 一、线程池的引入背景及重要性 在现代软件开发中,特别是在基于Java的应用程序设计中,线程池技术已经成为提高系统性能和资源利用率的关键手段之一。线程池...
MySQL的线程池原理是MySQL 5.6版本引入的一项重要优化,旨在提高数据库在高并发场景下的性能和资源利用率。传统的线程模型是“一对一”模式,即每个客户端连接到MySQL服务器时,服务器都会创建一个新的线程来处理该...
线程池原理及创建(C++实现) 本文将详细介绍线程池的原理和创建过程,并提供一个通用的线程池框架,具有动态伸缩性,可以根据执行任务的轻重自动调整线程池中线程的数量。 线程池的必要性 在高并发的服务器环境...
### VC线程池原理及实现方法 #### 一、引言 随着计算机网络技术的发展,服务器需要处理大量的并发请求,而传统的多线程方案在处理这些请求时面临着效率低下和资源浪费的问题。为了提高服务器的响应能力和处理能力,...
1. **线程池初始化**:在应用程序启动时,线程池会创建一定数量的空闲线程(N1),这些线程处于阻塞状态,不消耗CPU资源,但占用一定的内存。 2. **任务提交**:当有新任务提交到线程池时,线程池会选择一个空闲...
### 线程池原理及模块设计 #### 一、线程池原理 在现代软件开发中,线程池技术是一种高效地管理线程的方法,它通过预创建一定数量的线程并将其维持在一个池中,以备随时使用。这种方法能够显著减少线程创建和销毁...
线程池的工作原理主要是通过维护一组可重用的线程来实现的。当任务到来时,线程池会从现有的线程中选择一个未被使用的线程来执行任务,而不是每次都创建新的线程。这降低了线程创建的延迟,提高了应用程序的响应速度...
### 线程池原理及创建(C++实现) #### 一、线程池的重要性 在现代计算机系统中,特别是网络服务器领域,如Web服务器、邮件服务器和数据库服务器等,面临着一个共同挑战:如何高效地处理短时间内大量涌入的连接...
线程池的设计和实现是一种高效的线程管理方式,它能够显著减少线程创建和销毁的开销,提高系统响应速度和并发能力。通过CThreadManage、CThreadPool、CWorkerThread、CJob以及线程同步机制的合理设计,可以构建出一...
### 线程池原理与实现(C++) #### 一、引言 线程池是一种常见的多线程处理框架,被广泛应用于各种高性能服务端应用程序中,如Web服务器、邮件服务器、数据库服务器等。线程池的主要目的是提高程序响应速度和资源...
本文将详细介绍线程池技术的基本原理、优势以及其实现方式,并探讨其在工作流引擎中的具体应用案例。 #### 1. 线程池技术的优点 线程池技术的主要优点包括: 1. **控制线程数量**:通过预设固定数量的线程,避免...
线程池是一种线程管理机制,用于减少在多线程应用中频繁创建和销毁线程的开销,提高程序性能和资源利用率。在C++中实现线程池,通常需要以下核心组件和概念: 1. 线程池管理器(CThreadManage):它是用户与线程池...
### C# CLR原理与线程池详解 #### 一、CLR与.NET框架 **CLR**(Common ...通过掌握MSIL、程序集、CTS、元数据、反射、命名空间和线程池等概念,开发者可以更好地利用.NET框架的强大功能,构建高质量的应用程序。
### C++线程池实现原理分析 #### 一、引言 线程池是一种软件设计模式,用于管理和控制大量线程的创建与销毁,尤其是在处理大量短期任务时,它可以显著提高程序性能。线程池的核心思想是预先创建一组线程,并让它们...
首先,我们需要了解线程池的基本原理。线程池是由系统维护的一个线程集合,当需要执行新任务时,它会从线程池中分配一个已准备好的线程,而不是每次都创建新的线程。这样可以减少线程的创建和销毁时间,提升程序的...
通过以上知识点的详细介绍和实际代码示例,文章帮助开发者深入理解Django中异步任务线程池的实现原理,以及如何在实际项目中利用这些原理来提高程序的性能和响应速度。这对于提升大规模数据处理能力、优化用户体验...
Java线程池是一种高效管理线程的工具,它允许开发者预先创建一组线程,当...在实际应用中,应根据系统需求和负载情况合理配置线程池的参数,如核心线程数、最大线程数、工作队列大小等,以达到最佳性能和资源利用率。