`
westlifesz
  • 浏览: 118284 次
社区版块
存档分类
最新评论

一个线程池实例(继续)

阅读更多

2006.12.12花了3个小时把 一个线程池实例 这篇文章讲的线程池例子读明白了!下面是这个程序的注释,以后再加上心得体会。

import java.util.Vector;

public class ThreadPool {
public static final int MAX_THREADS = 100; //最大线程数
public static final int MAX_SPARE_THREADS = 50; //最大空闲线程数
public static final int MIN_SPARE_THREADS = 10; //最小空闲线程数
public static final int WORK_WAIT_TIMEOUT = 60 * 1000; //超时时间

protected Vector pool; //类全局变量,装线程的,里面加入ControlRunnable实例
protected MonitorRunnable monitor; //监控线程内部类全局变量
protected int maxThreads;
protected int minSpareThreads;
protected int maxSpareThreads;
protected int currentThreadCount;
protected int currentThreadsBusy;
protected boolean stopThePool;

public ThreadPool() {
maxThreads = MAX_THREADS;
maxSpareThreads = MAX_SPARE_THREADS;
minSpareThreads = MIN_SPARE_THREADS;
currentThreadCount = 0;
currentThreadsBusy = 0;
stopThePool = false;
}

public synchronized void start() {
adjustLimits();
openThreads(minSpareThreads);

//启动监控线程,程序开始运行
monitor = new MonitorRunnable(this);
}

public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
}

public int getMaxThreads() {
return maxThreads;
}

public void setMinSpareThreads(int minSpareThreads) {
this.minSpareThreads = minSpareThreads;
}

public int getMinSpareThreads() {
return minSpareThreads;
}

public void setMaxSpareThreads(int maxSpareThreads) {
this.maxSpareThreads = maxSpareThreads;
}

public int getMaxSpareThreads() {
return maxSpareThreads;
}

/*
这个方法给外部调用,把具体的任务传进来。从这个方法可以看到,它实际上是把任务接过来,判断当前线程有多少,有空闲的就到池里面去取,实际上是调用池里面的ControlRunnable线程来干活!
为什么要通过它呢,因为它是ThreadPool类的方法,总协调人,来管理pool,线程数等东西。而ControlRunnable线程就是只管干活的,是在pool里面真正干活的线程。
*/
public void runIt(ThreadPoolRunnable r) {
if (null == r) {
throw new NullPointerException();
}
if (0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
ControlRunnable c = null;
synchronized (this)
{
//刚开始的时候currentThreadCount是 start() 里调用的 openThreads(minSpareThreads) 方法的minSpareThreads参数设置的,是10个。刚开始(第一个任务进来),currentThreadsBusy是为零,所以下面的if条件部成立,运行下去到currentThreadsBusy++;就表示有个线程在忙了!
if (currentThreadsBusy == currentThreadCount)
{
if (currentThreadCount < maxThreads) {
int toOpen = currentThreadCount + minSpareThreads;
openThreads(toOpen);
} else {
while (currentThreadsBusy == currentThreadCount) {
try {
this.wait();
}catch (InterruptedException e) {
}
if (0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
}
}
}

//找到pool里最末端的一个线程。然后从pool里除去,currentThreadsBusy加1,表示忙的线程多一个了。
c = (ControlRunnable) pool.lastElement();

/*
为什么要把我从池里面摘掉呢?难到以后还把我加进来?对了!在ControlRunnable里面运行完任务后,会调用 returnController 方法,returnController方法的参数就是removeElement掉的这个ControlRunnable,又加进到pool来了。
*/
pool.removeElement(c);
currentThreadsBusy++;
}
c.runIt(r); //上面从pool里取出来线程了ControlRunnable,调用它的runIt方法,开始运行!
}

public synchronized void shutdown() {
if (!stopThePool) {
stopThePool = true;
monitor.terminate();
monitor = null;
for (int i = 0; i < (currentThreadCount - currentThreadsBusy); i++) {
try {
((ControlRunnable) (pool.elementAt(i))).terminate();
} catch (Throwable t) {
}
}
currentThreadsBusy = currentThreadCount = 0;
pool = null;
notifyAll();
}
}

protected synchronized void checkSpareControllers() {
if (stopThePool) {
return;
}

//如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程
if ((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
int toFree = currentThreadCount - currentThreadsBusy - maxSpareThreads;
for (int i = 0; i < toFree; i++) {
//
ControlRunnable c = (ControlRunnable) pool.firstElement();
pool.removeElement(c);
c.terminate();
currentThreadCount--;
}
}
}

protected synchronized void returnController(ControlRunnable c) {
if (0 == currentThreadCount || stopThePool) {
c.terminate();
return;
}
currentThreadsBusy--;

pool.addElement(c); //把开始pool.removeElement(c);掉的ControlRunnable线程加进来。
notify(); //加进来就加进来了,还通知谁?难道有人在等你?
}

protected synchronized void notifyThreadEnd() {
currentThreadsBusy--;
currentThreadCount--;
notify();
openThreads(minSpareThreads);
}

protected void adjustLimits() {
if (maxThreads <= 0) {
maxThreads = MAX_THREADS;
}
if (maxSpareThreads >= maxThreads) {
maxSpareThreads = maxThreads;
}
if (maxSpareThreads <= 0) {
if (1 == maxThreads) {
maxSpareThreads = 1;
} else {
maxSpareThreads = maxThreads / 2;
}
}
if (minSpareThreads > maxSpareThreads) {
minSpareThreads = maxSpareThreads;
}
if (minSpareThreads <= 0) {
if (1 == maxSpareThreads) {
minSpareThreads = 1;
} else {
minSpareThreads = maxSpareThreads / 2;
}
}
}

/*
刚开始时由ThreadPool的start()调用,toOpen = minSpareThreads = 10. 刚开始运行的时候,线程池会往Vector对象里装入minSpareThreads个元素,每个元素都是ControlRunnable线程类,ControlRunnable类在其构造方法中启动线程。
*/
protected void openThreads(int toOpen) {
if (toOpen > maxThreads) {
toOpen = maxThreads;
}
if (0 == currentThreadCount) {
pool = new Vector(toOpen); //初始开minSpareThreads 10个元素
}

/*
每个元素是ControlRunnable(this)内部类,ControlRunnable的通过构造方法里面开始干活了!
*/
for (int i = currentThreadCount; i < toOpen; i++) {
pool.addElement(new ControlRunnable(this)); //new ControlRunnable,把它加进去
}
currentThreadCount = toOpen; //当前线程个数,就是上一步addElement加进去的。
}

/* 监控线程的内部类,为什么要用一个类呢?而不用个方法?因为是个类的话,它可以执行Runnable接口,为什么要继承Runnable接口呢?因为要在这里面开个线程,而这个线程干什么事呢?就是执行Runnable的run()方法-》监控当前线程个数:如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程.这个内部类是在
star()方法里通过 monitor = new MonitorRunnable(this); 开始运行. 这个内部类就是一直在监控线程数量,起到这么个作用。(当然还有个terminate()方法,来中止运行程序的。
*/
class MonitorRunnable implements Runnable {
ThreadPool p;
Thread t;
boolean shouldTerminate;

//构造方法把一个ThreadPool实例传过来
MonitorRunnable(ThreadPool p) {
shouldTerminate = false;
this.p = p; //保存ThreadPool实例给自己

t = new Thread(this); //new一个线程
t.start(); //开始运行一个线程,运行下面的run()方法:
}
public void run() {
while (true) {
try {
synchronized (this) {
this.wait(WORK_WAIT_TIMEOUT);
}
if (shouldTerminate) { //中止运行吗?
break;
}

/*
一直检测当前线程数,如果当前线程个数 - 正在繁忙的线程 比 最大空闲线程数大,释放多的线程,具体见ThreadPool的checkSpareControllers方法
*/
p.checkSpareControllers();
} catch (Throwable t) {
t.printStackTrace();
}
}
}

public synchronized void terminate() {
shouldTerminate = true; //中止运行程序
this.notify();
}
}

/*
又是一个执行Runnable接口的内部类,这个线程类是在Vector pool里面,具体运行扔给它的任务,和上面监控内部类一样,这个执行Runnable接口里面new thread线程,开始干活了!
*/
class ControlRunnable implements Runnable {
ThreadPool p;
Thread t;
ThreadPoolRunnable toRun; //具体要运行的任务
boolean shouldTerminate;
boolean shouldRun;
boolean noThData;
Object thData[] = null; //对象数组

/*
ControlRunnable类的构造方法,在构造方法里即开始new Thread,开始run()。
*/
ControlRunnable(ThreadPool p)
{
toRun = null;
shouldTerminate = false;
shouldRun = false;
this.p = p;
t = new Thread(this);
t.start();
noThData = true;
thData = null;
}


public void run() {
while (true) { //在一个循环里面开始工作
try {
synchronized (this) {
/*
刚开始shouldRun和shouldTerminate都是false,这个线程一直在这等wait(),
等待别人notify()。
*/
if (!shouldRun && !shouldTerminate) {
this.wait();
}
}
//如果调用了它自己的terminate()方法,里面会设置shouldTerminate为true,就break,不干了!
if (shouldTerminate) {
break;
}

/*
这个线程到这里就是开始干活了!肯定是某个调用了它自己的runIt()方法,因为这个方法里面有 shouldRun = true; 和 this.notify(); notify()把上面的wait();唤醒了,别睡了,干活吧!
而且runIt(ThreadPoolRunnabletoRun)里面会传过来一个ThreadPoolRunnable实例,就是真正要做的事情,有任务来了,开干!!
*/
try {
if (noThData) {
thData = toRun.getInitData();
noThData = false;
}
if (shouldRun)
{
//具体的任务类。我把线程给你开了,现在你有事情做,就做你自己的事吧。just do it!
toRun.runIt(thData);
}
} catch (Throwable t) {
System.err.println("ControlRunnable Throwable: ");
t.printStackTrace();
shouldTerminate = true;
shouldRun = false;
p.notifyThreadEnd();
}

//跑到finally这来了,肯定事干完了,把shouldRun设为false,然后调用returnController,把这个线程又加到pool里去!
finally {
if (shouldRun) {
shouldRun = false;
p.returnController(this);
}
}
if (shouldTerminate) {
break;
}
} catch (InterruptedException ie) {
}
}
}

public synchronized void runIt(ThreadPoolRunnable toRun) {
if (toRun == null) {
throw new NullPointerException("No Runnable");
}
this.toRun = toRun;
shouldRun = true;
this.notify();
}

//中止运行这个线程,并告诉 this.notify() 别人( this.wait() )不等了;
public synchronized void terminate() {
shouldTerminate = true;
this.notify();
}
}
}

分享到:
评论

相关推荐

    一个完整的线程池的实例

    2. **`Worker` 类**:这是一个内部类,继承自`Thread`,负责实际的任务执行。 - `runner`:当前`Worker`正在执行的`Runnable`任务。 - `wakeup` 方法:用于唤醒当前处于等待状态的`Worker`,使其开始执行新的任务...

    C++线程池实例

    总结来说,“C++线程池实例”是一个展示了如何在C++环境中,特别是在较旧的编译器如VC6.0下,利用线程池来实现并发任务处理的例子。通过理解和实践这个实例,开发者可以更好地理解线程池的原理和使用,提高软件的...

    Windows下一个比较完美的线程池实现和示例

    Windows下一个比较完美的线程池实现和示例 本线程池提供了如下功能: 1.能根据任务个数和当前线程的多少在最小/最大线程个数之间自动调整(Vista后的系统有 SetThreadpoolThreadMaximum 等函数有类似功能); 2.能方便...

    Java并发之串行线程池实例解析

    Java并发之串行线程池实例解析是Java并发编程中非常重要的一部分,今天我们就来详细介绍如何实现一个串行的线程池实例。在介绍之前,首先我们需要了解什么是串行线程池。串行线程池是指一个线程池中只有一个线程在...

    线程池代码

    - 当某个工作线程完成任务后,它会从队列中取出下一个任务继续执行,直到线程池关闭或者任务队列为空。 - 如果线程池的大小达到最大限制并且任务队列也已满,新提交的任务将根据拒绝策略进行处理,如丢弃任务或抛...

    Java/Android线程池演示Demo

    线程池是由多个工作线程组成的集合,它可以预先创建一定数量的线程,当有任务需要执行时,从池中取出一个线程来执行任务,任务完成后,线程不立即销毁,而是返回到线程池中等待下一个任务。这种方式避免了频繁创建和...

    java 打造阻塞式线程池的实例详解

    Java 打造阻塞式线程池是指在 Java 中创建一个线程池,並且该线程池可以阻塞式地执行任务,直到线程池的队列中有可用的线程资源时,才继续执行任务。这种线程池的优点是可以避免线程池中的线程溢出,避免了对系统的...

    C#线程池 所有线程运行完毕

    当我们需要执行大量短生命周期的任务时,线程池是一个非常理想的选择。 线程池的工作原理是:当任务被提交到线程池时,线程池会根据当前系统负载和已有的线程数量,决定是否立即创建新线程执行任务,或者将任务放入...

    线程池管理多线程上传

    线程池管理和多线程上传是并发编程中的一个重要实践,特别是在大数据传输和网络服务中。在Java等编程语言中,线程池通过有效地管理和复用线程资源,避免了频繁创建和销毁线程带来的开销,提升了系统性能。下面将详细...

    线程池源码解析-多线程

    在Java线程池的实现中,`ctl`变量是一个`AtomicInteger`实例,用于存储线程池的状态和当前工作线程的数量。`ctl`的值是由两部分组成的:高三位表示线程池的状态,低29位表示工作线程的数量。线程池的状态有以下五种...

    线程池的使用介绍Demo,简单明了。

    在`ThreadPoolDemo`中,我们可以创建一个ThreadPoolExecutor实例,并提交Runnable任务。示例代码如下: ```java ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池 for (int i...

    创建Java程序中线程池的详解

    `ExecutorService` 是一个接口,提供了管理和控制线程池的功能,而 `ThreadPoolExecutor` 是其具体实现,可以通过构造函数自定义线程池的参数,如核心线程数、最大线程数、线程存活时间、任务队列类型等。...

    Java并发编程:线程池的使用 - 平凡希 - 博客园1

    4. `workQueue`:工作队列,一个阻塞队列,用于存放待执行的任务。当线程池和工作队列都满时,新提交的任务将触发拒绝策略。 5. `threadFactory`(可选):线程工厂,用于创建新线程。如果不指定,系统会使用默认的...

    C#Winform异步多线程和线程池集成的用法

    线程是操作系统分配CPU时间的基本单元,每个进程至少包含一个线程。在C#中,可以使用`System.Threading.Thread`类来创建和管理线程。通过创建新的线程实例并调用其`Start()`方法,我们可以在后台执行耗时任务,避免...

    使用Java匿名内部类实现一个简单的线程池.txt

    每个任务都是一个匿名内部类实现的`Runnable`接口的实例,其中的`run()`方法定义了任务的具体逻辑。这里使用了`executor.execute(task)`来提交任务,`execute()`方法会在线程池中找到一个空闲的线程来执行该任务。 ...

    Python 应用之线程池.pdf

    在当前的IT运维领域,随着运维对象数量的激增,如何高效地处理大量维护对象成为了一个亟待解决的问题。本文将重点探讨Python语言在构建线程池方面的应用,以及在面对大量维护对象时,如何利用线程池来提高处理任务的...

    线程池处理委托 返回布尔(多线程处理)

    在标题所提及的“线程池处理委托 返回布尔(多线程处理)”中,我们可能会创建一个委托类型,该类型定义了一个返回布尔值的方法签名。例如: ```csharp public delegate bool MyDelegate(); ``` 然后,我们可以...

    C# 简单MSSQL线程池+异步SOCKET服务端完整源码

    结合以上知识点,提供的源码应该是一个运行中的示例,演示了如何在C#中利用线程池处理来自多个客户端的异步SOCKET请求,并同时与MSSQL数据库进行交互。这对于初学者来说是一个很好的学习资源,它涵盖了多种基础但...

    JAVA线程池应用.pptx

    线程池是Java多线程编程中的一个重要概念。它通过管理一组多线程的方式,为应用程序提供了一种更加灵活高效的线程管理机制。相比于直接创建线程,使用线程池可以有效地控制系统中的线程数量,避免了因大量创建销毁...

    day07【线程池、Lambda表达式】(1).md

    - `Executors`:静态工厂方法,用于创建不同类型的线程池实例。 - `ScheduledThreadPoolExecutor`:扩展 `ThreadPoolExecutor`,支持定时任务执行。 - **主要配置参数**: - `corePoolSize`:线程池的基本大小。 ...

Global site tag (gtag.js) - Google Analytics