【问题标题】:worker thread is not notified in multithread code多线程代码中未通知工作线程
【发布时间】:2016-03-09 02:11:26
【问题描述】:

我想用 Java 编写一个传统的生产者和消费者多线程程序。生产者线程将向线程安全列表发送消息,直到该列表已满。一旦缓冲区已满,它将通知工作线程并清除缓冲区。在我的编码中,没有通知工作线程。

你知道原因吗?谢谢。

package com;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadTest {

    public static void main(String[] args) {

        final List<String> bufferSafeList = Collections.synchronizedList(new ArrayList<String>());

        final ReentrantLock bufferLock = new ReentrantLock();
        final Condition bufferFull = bufferLock.newCondition();
      //  final Condition bufferEmpty = bufferLock.newCondition();

        Thread producerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        bufferLock.lock();
                        bufferSafeList.add(System.currentTimeMillis() + "");
                        System.out.println("add to buffer " + bufferSafeList.size());
                        if (bufferSafeList.size() > 100) {
                            System.out.println("send wake up signal");
                            bufferFull.signalAll();

                            //waiting for buff cleared
                            while(!bufferSafeList.isEmpty()){
                                Thread.sleep(1000);
                            }                           
                        }

                         Thread.sleep(1000);
                    } catch(Exception e){
                        e.printStackTrace();
                    }
                    finally {
                        bufferLock.unlock();
                    }
                }
            }
        });
        producerThread.start();

        Thread workerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        bufferLock.lock();
                        System.out.println("waiting for wakeup signal");
                        bufferFull.await();
                        System.out.println("clear buffer");

                        bufferSafeList.clear();                      
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    } finally {
                        bufferLock.unlock();
                    }
                }
            }
        });
        workerThread.start();
    }

}

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    你在finally中只有unlockbufferLock,所以workerThread永远无法比尝试获得lock更进一步

    当缓冲区已满时unlock 以便workerThread 可以继续

    【讨论】:

    • 我把解锁直接放在bufferFull.signalAll()之后;还是不行。
    • 发信号前您需要unlock
    【解决方案2】:

    如果生产者线程碰巧先运行,因为它很可能首先启动,它可能会首先锁定bufferLock,在这种情况下,它将填充列表并在消费者运行时调用bufferFull.signalAll()仍在等待获取锁。然后,您忙于等待工作人员清除列表,它永远不会这样做,因为它无法继续。

    而且,即使您在发出信号后解锁了锁,也为时已晚。当工作人员await()处理条件时,信号已经来了又走了。实际上,即使生产者等待获取锁,直到它准备好发出信号,也存在竞争条件。

    条件变量的正确使用总是涉及测试在等待之前是否满足预期条件,如果在从等待中恢复后不满足则循环返回等待更多。您可以通过实现这一点来克服代码中的竞争。

    【讨论】:

    • 你有正确使用条件变量的链接吗?
    • @EdwardChen,在the API docs for java.util.concurrent.locks.Condition的描述部分怎么样?或者这与使用所有Objects 提供的较低级别wait()/notify() 方法的通常模式非常相似,您肯定可以在没有帮助的情况下找到多个关于此的教程。这也不是严格意义上的 Java 问题。 Google 似乎对这个主题非常有用。
    猜你喜欢
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    相关资源
    最近更新 更多