我很早就知道线程池这个概念,但是一直没有机会使用到,我对线程池的一个比较深刻的认识就是线程池中的线程是个数限制的,一次性构造全部但是是可以重用的,不需要每次都去构造一个新的。但是最近我做项目的做到了相关的技术,发现好像并不是这么一回事。。。
public class MyThread implements Runnable{ public MyThread() { System.out.println("construct..."); } public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(2); for(int i = 0; i < 10; i++){ service.submit(new MyThread()); } } public void run() { try{ System.out.println("run..."); Thread.sleep((long) (Math.random()*1000)); }catch(Exception e){ } } }
这是我写的一个很简单的测试类,运行后发现构造函数被调用了10次(我觉的如果能重用的话调用两次就够了吧),那我就纳闷了,线程池中的线程真的可以做到重用吗?还是我的写法有问题?还是我的认识从根本上就是错误的?
[quote]new MyThread 10次,当然构造函数10次。
Executors.newFixedThreadPool(2); 创建了有2个线程的线程池,这两个线程可复用,并且同时只有两个线程执行,多余2个任务等待被执行。
[/quote]
Executors.newFixedThreadPool(2); 是创建一个有2个线程的线程池。
service.submit(new MyThread()); 是向线程池中添加需要执行的任务,而不是向线程池添加线程
[quote]
问题补充:
先感谢aninfeel和lewhwa的热心帮助,现在我比较关心的是使用Executors创建的线程池如何做到线程重用?是不能用new(如:service.submit(new MyThread());)来创建线程吗?
[/quote]
Executors.newFixedThreadPool(2); 创建的2个线程是被重用的。
service.submit(new MyThread()); 向线程池中添加的任务,线程池是不会负责的。
因为你使用new MyThread()已经10次了,构造函数被调用10次是必然的。
对于线程池,如果使用1.4以前的jdk,自己设计线程池时,池里放到肯定是已经启动的线程类。但是newFixedThreadPool怎么实现的,想追根问底就参考这里吧——
http://kickjava.com/src/java/util/concurrent/Executors.java.htm
[quote]这是我写的一个很简单的测试类,运行后发现构造函数被调用了10次(我觉的如果能重用的话调用两次就够了吧),那我就纳闷了,线程池中的线程真的可以做到重用吗?还是我的写法有问题?还是我的认识从根本上就是错误的?[/quote]
new MyThread 10次,当然构造函数10次。
Executors.newFixedThreadPool(2); 创建了有2个线程的线程池,这两个线程可复用,并且同时只有两个线程执行,多余2个任务等待被执行。
[quote]
我可以这样理解吗:service.submit(new MyThread())执行的时候实际上是调用Executors.newFixedThreadPool(2)这步中创建的两个线程,并且这两个线程是可以重用的,然后通过这两个可重用的线程去调用MyThread,从而达到线程重用的目的吗?
[/quote]
嗯
[quote]我可以这样理解吗:service.submit(new MyThread())执行的时候实际上是调用Executors.newFixedThreadPool(2)这步中创建的两个线程,并且这两个线程是可以重用的,然后通过这两个可重用的线程去调用MyThread,从而达到线程重用的目的吗? [/quote]
正确!同时执行的线程只要2个。其它提交的线程如果大于2,等待人家执行过后再执行。
线程重用的核心是,它把Thread.start()给屏蔽起来了(一定不要重复调用),然后它自己有一个Runnable.run(),循环在跑,跑的过程中不断检查我们是否有新加入的子Runnable对象,有就调一下我们的run(),其实就一个大run()把其它小run()#1,run()#2,...给串联起来了,基本原理就这么简单。
JDK代码节选
/**
* Main run loop
*/
public void run() {
try {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
runTask(task);//这里最终会调用task.run()
task = null;
}
} finally {
workerDone(this);
}
}
}