【问题标题】:notifyAll() does not worknotifyAll() 不起作用
【发布时间】:2015-09-10 07:49:51
【问题描述】:

在下面的代码中,notifyAll() 被调用但不会重新激活其他线程。我得到的输出是

  • beta 等待收到通知的时间:1441870698303,activeWriters:1

  • alpha 等待收到通知的时间:1441870698303,activeWriters:1

  • delta notify all at time: 1441870698403, activeWriters: 0

    公共类 Waiter 实现 Runnable{

        private static int activeWriters;
    
        public Waiter(Message msg){
        }
    
        @Override
        public void run() {
            beforeWrite();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            afterWrite();
        }
    
        protected synchronized void beforeWrite(){
            while (activeWriters > 0 ) {
                try {
                    System.out.println(Thread.currentThread().getName() +" waiting to get notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
                    wait();
                    System.out.println(Thread.currentThread().getName() +" waiting got notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            ++activeWriters;
        }
        protected synchronized void afterWrite(){
            --activeWriters;
            System.out.println(Thread.currentThread().getName() +" notify all at time: "+System.currentTimeMillis() + ", activeWriters: " + activeWriters);
            notifyAll();
        }
    
    }
    
    public class WaitNotifyTest {
    
        public static void main(String[] args) {
            Message msg = new Message("process it");
            Waiter waiter1 = new Waiter(msg);
            Waiter waiter2 = new Waiter(msg);
            Waiter waiter3 = new Waiter(msg);
            new Thread(waiter1,"alpha").start();
            new Thread(waiter2, "beta").start();
            new Thread(waiter3, "delta").start();
    
        }
    
    }
    

【问题讨论】:

    标签: java multithreading concurrency wait


    【解决方案1】:

    wait()notify*() 调用在指定对象上工作,这意味着 notify*() 唤醒在同一对象上调用 wait() 的线程。

    在您的情况下,您在 3 个未连接的不同对象上调用 wait()notifyAll(),因此这是行不通的。

    您可以添加静态互斥锁:

    private static final Object mutex = new Object();
    

    然后在这个对象上调用wait()notify*()。记得先在互斥锁上同步:

    synchronized (mutex) {
        ...
        mutex.wait();
        ...
    }
    

    和:

    synchronized (mutex) {
        ...
        mutex.notifyAll();
        ...
    }
    

    activeWriters 的所有访问权都必须在这些synchronized 块中,原因有两个。目前对它的访问实际上是不同步的,因为您在 3 个不同的对象上同步。除此之外,activeWriters 是您的条件变量,并且您希望 notify*() 它更改的其他线程。为此,变量的更改和notify*() 调用必须在同一个synchronized 块中。

    【讨论】:

    • 谢谢你的答案。我现在看到这 3 个线程之间确实没有联系。如果我理解正确我的方法 beforeWrite 应该更改为 protected void beforeWrite(){ synchronized (mutex) { while (activeWriters > 0 ) { try { mutex.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } ++activeWriters; } }
    • @user3637488 是的,同样适用于第二种方法。
    • 非常感谢这个工作。 ps 很抱歉评论中的代码格式错误:)
    • 我对并发做了一些额外的研究。由于多个线程访问此变量,我的代码中“activeWriters”的声明应该是“private static volatile int activeWriters”是否更正确?
    • @user3637488 如果您总是从synchronized 块访问共享变量,则不需要volatile
    【解决方案2】:

    您的程序存在重大设计缺陷。

    您正在创建 3 个独立的 Waiter 类实例,并希望它们都以同步方式访问 activeWriters。这是不可能的,因为实例方法会获取不同的锁,但会修改相同的静态变量activeWriters

    要提供静态变量并发访问,您应该通过访问它们。同步静态方法。 一种方法是使beforeWrite()afterWrite() 方法static

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-10
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多