Java 生产者-消费者模式:按需线程
考虑以下类别:Java 生产者-消费者模式:按需线程,java,multithreading,Java,Multithreading,考虑以下类别: public class TaskWorkDemo { private final Object mLock = new Object(); private final ArrayDeque<String> mQueue = new ArrayDeque<String>(); private Thread mThread; private String getOne(){ synchronized (mLo
public class TaskWorkDemo {
private final Object mLock = new Object();
private final ArrayDeque<String> mQueue = new ArrayDeque<String>();
private Thread mThread;
private String getOne(){
synchronized (mLock){
return mQueue.isEmpty() ? null : mQueue.peek();
}
}
//--produce--
private void putOne(String s){
synchronized (mLock){
mQueue.offer(s);
}
//-- at time T --
if(mThread == null || !mThread.isAlive()){
mThread = new Thread(new Runner());
mThread.start();
}
}
private class Runner implements Runnable{
//--consume--
@Override
public void run() {
String s = getOne();
while (s != null){
System.out.println(s);
s = getOne();
}
//-- at time T --
mThread = null;
}
}
}
公共类TaskWorkDemo{
私有最终对象mLock=新对象();
private final ArrayDeque mQueue=new ArrayDeque();
私有线程mThread;
私有字符串getOne(){
已同步(mLock){
返回mQueue.isEmpty()?null:mQueue.peek();
}
}
//--产生--
私有void putOne(字符串s){
已同步(mLock){
多个报价;
}
//--在时间T--
if(mThread==null | |!mThread.isAlive()){
mThread=新线程(newrunner());
mThread.start();
}
}
私有类运行器实现可运行{
//--消耗--
@凌驾
公开募捐{
字符串s=getOne();
while(s!=null){
系统输出打印项次;
s=getOne();
}
//--在时间T--
mThread=null;
}
}
}
只有当队列中存在挂起的字符串时,使用者线程才应该存在,即不像我们看到的典型用法那样在队列中等待。所以,我试图在每次向队列中添加某个线程时创建一个线程,方法是检查之前的线程是否不存在或是否已完成
但这种方法有一个极端情况(请参见上文代码中时间T的/--
):使用者线程已退出循环,但尚未完成。生产者线程将要检查前一个消费者线程是否仍然存在,它将发现它仍然在完成,并跳到创建一个新线程
有什么想法吗?您可以使用JDK ThreadPoolExecutor。它允许您指定最小线程数(在您的情况下为零)、最大线程大小(在您的情况下为一个)和保持活动超时(队列为空时线程将挂起的时间)。如果
putOne
被稀疏调用,则不会发生争用条件。如果它经常被调用,那么不应该使线程为空
(此答案假设这是一种练习,因为它显然不是在多线程环境中实现生产者-消费者算法的方法)您不应该将
mThread
设置为null,因为它最终会导致NullPointerException
:
mThread=null
!mThread.isAlive()
,它抛出一个NullPointerException
ThreadPoolExecutor
来解决您的问题,但是如果出于某种原因您不能/不会这样做,那么您可以替换您的
if(mThread == null || !mThread.isAlive())
病况
while(mThread.isAlive()) {
sleep(sleep_parameter);
}
// mThread is no longer alive
mThread = new Thread(new Runner());
mThread.start();
循环,它将循环直到线程终止。比睡眠更有效的替代方法是使用
信号量
,以便使用者可以在其线程即将终止时发出信号(生产者将许可证为零的信号量
传递给消费者,然后对信号量调用获取
,导致其阻塞;消费者在信号量即将终止时调用释放
,唤醒生产者)感谢您的回复。我认为,如果while loop每次都能升起一个标志,那么另一轮就要到期了,线程创建逻辑应该跳过创建新线程。当有两个线程时,会有一个短暂的时刻,但时间很短。它还应该是一个锁(或者至少是volatile关键字)在mThread重启前后,否则如果同时从多个线程调用putOne
,它可能会启动多个使用者线程。同时,while睡眠将锁定生产者线程,这可能也是不需要的。