请java大拿们看看,线程池的一个疑惑问题,关于任务队列的几个为什么....

toss2000 2011-12-16 05:17:08
先上代码,从网上得来的,贴一下主要部分:
public final class ThreadPool
{
private static List<Task> taskQueue = Collections.synchronizedList(new LinkedList<Task>());
private ThreadPool()
{
workers = new PoolWorker[5];
for (int i = 0; i < workers.length; i++)
{
workers[i] = new PoolWorker(i);// 在线程池里生成多个线程并且全部进入启动状态
}
}
....
public void batchAddTask(Task[] taskes)
{
synchronized (taskQueue)
{
for (int i = 0; i < taskes.length; i++)
{
taskes[i].setTaskId(++taskCounter);
taskQueue.add(taskes[i]);
}
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}

private class PoolWorker extends Thread
{
public void run()
{

while (isRunning)
{
Task r = null;
synchronized (taskQueue)// 加synchronized的作用是避免几个线程同时执行一个task
{
while (taskQueue.isEmpty())
{
try
{
taskQueue.wait(20);
}
catch (Exception ie)
{

}
}

r = (Task) taskQueue.remove(0);
}
}

}

我不明白的地方是对于代码
while (taskQueue.isEmpty())
{
try
{
taskQueue.wait(20);
}
这一段,意思就是只要队列taskQueue为空就循环等待,我不明白为什么要加这个等待,只要为空就一直循环不就行了,之后不为空了应该自动跳出循环直接执行r = (Task) taskQueue.remove(0);不就完了吗...可是我把taskQueue.wait(20);去了后 ,循环一直退不出来,就是说一直没办法执行到 r = (Task) taskQueue.remove(0);语句....

后来我认为是上面这段代码有问题
taskQueue.notifyAll();
因为当时觉得,队列赋值了就可以用了,还通知什么,就把这段也去了,结果
while (taskQueue.isEmpty())
{
try
{

}
这个循环还是没完没了...

但是把这两段代码都加上就没有问题,程序可以正常运行,请高手指点,为什么会这样?为什么有了taskQueue.notifyAll();和 taskQueue.wait(20);程序就能正常运行呢?
...全文
218 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
toss2000 2011-12-20
  • 打赏
  • 举报
回复
谢谢大家关注,主要就是想了解一下线程池的实现
Jaya1989 2011-12-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 bao110908 的回复:]

你自己实现线程池啊?我劝你不要这么做哦!

JDK 1.5 开始有 ThreadPoolExecutor 类了,没有必要再去自己实现了。一个线程池的实现非常复杂,普通开发人员根本不可能完成。

涉及到“池”的东西,不管是实例池、数据库连接池,还是线程池,他们的实现都是极其复杂的。如果不是精于这些东西的话,要想实现并且能运用在实际中,那就是不可能的任务。

线程池的实现,我粗粗地列举了……
[/Quote]
关注火龙果的回复。
济南大飞哥 2011-12-19
  • 打赏
  • 举报
回复
不懂!!!!!!!
  • 打赏
  • 举报
回复
你自己实现线程池啊?我劝你不要这么做哦!

JDK 1.5 开始有 ThreadPoolExecutor 类了,没有必要再去自己实现了。一个线程池的实现非常复杂,普通开发人员根本不可能完成。

涉及到“池”的东西,不管是实例池、数据库连接池,还是线程池,他们的实现都是极其复杂的。如果不是精于这些东西的话,要想实现并且能运用在实际中,那就是不可能的任务。

线程池的实现,我粗粗地列举了一下,以如下技术难点:

1:如果不是使用 java.util.concurrent.LinkedBlockingQueue 的话,那就需要自行实现一个阻塞的有界或者无界队列,用于存放等待的任务

2:线程池中的线程在运行时产生异常且处理不当,这时将会产生线程泄漏,也就是说线程池中的线程少了一个。一个可用的线程池在监测到这种情况出现时应该回收该泄漏的线程,并及时补充一个新的线程

3:线程池中的线程都在工作时,若还有任务加入进来,这时需要将其放入到队列之中,若池中的某个线程工作完了,需要及时通知队列中的任务附加到可用线程中去执行

-----------------------------------------------------------------------
线程池基本上是这样实现的:

1:先 new 出固定数量的 Thread,类似于这样:Thread t0 = new Thread(new WorkRunnable());

WorkRunnable 的结构基本上是这样的(实际远远比这复杂):

public class WorkRunnable implements Runnable {

private Runnable command;

public WorkRunnable(Runnable command) {
this.command = command;
}

public void run() {
command.run();
}

public void setCommand(Runnable command) {
this.command = command;
}
}


2:执行 t0.start() 可以执行线程,如果执行完了,将 WorkRunnable 中的 command 换一个再 start() 又可以执行了。

基本上的思路就是这样,但是实现起来极其复杂,不建议自己写,了解一下就可以了。

dracularking 2011-12-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 toss2000 的回复:]

我还是想求证一下对于语句
taskQueue.wait(20); 他的意思是让队列taskQueue自己阻塞20秒还是说让调用taskQueue.wait(20); 语句的线程 自己阻塞20秒?
[/Quote]
后者,或由notify或notifyAll唤醒

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.

toss2000 2011-12-19
  • 打赏
  • 举报
回复
我还是想求证一下对于语句
taskQueue.wait(20); 他的意思是让队列taskQueue自己阻塞20秒还是说让调用taskQueue.wait(20); 语句的线程 自己阻塞20秒?
龙四 2011-12-19
  • 打赏
  • 举报
回复
你做个死循环看看占用的cpu
toss2000 2011-12-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 lw_china 的回复:]

注意一点,while是在同步块中,如果没有wait的话,就不会释放锁,那么就不能把任务加入队列,所以队列一直是空,所以就一直循环了。

这个是同步的问题,你没能理解。

另外,wait除了释放锁之外还有降低cpu开销的意图。
[/Quote]
wait的作用不是让线程等待20秒吗?等了20秒之后接着开始运行,不是这个意思吗?
lw_China 2011-12-16
  • 打赏
  • 举报
回复
注意一点,while是在同步块中,如果没有wait的话,就不会释放锁,那么就不能把任务加入队列,所以队列一直是空,所以就一直循环了。

这个是同步的问题,你没能理解。

另外,wait除了释放锁之外还有降低cpu开销的意图。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧