0

考虑以下类:

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;
        }
    }
}

只有当队列中有待处理的字符串时,消费者线程才应该存在,即不像我们看到的典型用法那样在队列中等待。因此,我试图在每次将某些内容添加到队列时创建一个线程,方法是检查任何先前的线程是否不存在或已完成。

但是这种方法有一个极端情况(见//-- at time T --上面的代码):消费者线程已经退出循环,但还没有完成。生产者线程即将检查之前的消费者线程是否还在,它会发现它还在结束,并跳过创建一个新线程。

有任何想法吗 ?

4

3 回答 3

1

您不应该设置mThread为 null,因为它最终会导致NullPointerException

  1. thread1 检查mThread == null,返回 false
  2. 线程2套mThread = null
  3. thread1 检查!mThread.isAlive(),它抛出一个NullPointerException

正如 kan 在他的回答中所建议的那样,您可能应该使用 aThreadPoolExecutor来解决您的问题,但是如果由于某种原因您不能/不会这样做,那么您可以替换您的

if(mThread == null || !mThread.isAlive())

条件与

while(mThread.isAlive()) {
    sleep(sleep_parameter);
}
// mThread is no longer alive
mThread = new Thread(new Runner());
mThread.start();

循环,它将循环直到线程终止。比休眠更有效的替代方法是使用类似 a 的东西,Semaphore以便消费者可以在其线程即将终止时发出信号(生产者将Semaphore零许可的 a 传递给消费者,然后调用acquire导致其阻塞的信号量;消费者然后在信号量即将终止时调用release它,这会唤醒生产者)

于 2013-08-05T19:40:32.377 回答
1

您可以使用 JDK ThreadPoolExecutor。它允许您指定最小线程数(在您的情况下为零),最大线程大小(在您的情况下为一个)和保持活动超时(当队列为空时线程将挂起的时间)。

于 2013-08-05T19:28:38.500 回答
0

如果putOne被稀疏调用,则不会发生竞争条件。如果它经常被调用,那么你不应该取消线程。

(这个答案假设这是一种练习,因为它显然不是在多线程环境中实现生产者-消费者算法的方法)

于 2013-08-05T19:30:09.747 回答