生产者消费模式:按需线程

时间:2013-08-05 19:04:51

标签: 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 (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 --):消费者线程不在循环中,但尚未完成。生产者线程即将检查以前的消费者线程是否仍在,它会发现它仍然整理,并跳过创建一个新的。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

您不应将mThread设为null,因为它最终会产生NullPointerException

  1. thread1检查mThread == null,返回false
  2. thread2设置mThread = null
  3. thread1检查!mThread.isAlive(),它会抛出NullPointerException
  4. 你可能应该使用ThreadPoolExecutor来解决你的问题,正如kan在他的回答中所建议的那样,但如果由于某种原因你无法做到这一点,那么你可以替换你的

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

    带有

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

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

答案 2 :(得分:0)

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

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