对java同步的工作方式感到困惑

dri*_*ood 1 java multithreading synchronization

我有基于我在网上找到的示例的示例代码来说明如何使用wait()notify().让我在代码示例前面加上Java教科书所做的以下语句waitnotify.

线程不能在对象上调用wait或notify方法,除非它拥有该对象的锁定

现在看看这段代码和输出:

public class ThreadTester
{
    public class Message {
        private String msg;
        public Message(String str){ this.msg=str;}
        public String getMsg() { return msg; }
        public void setMsg(String str) { this.msg=str;} 
    }

    public class Waiter implements Runnable{         
        private Message msg;
        public Waiter(Message m){
            this.msg = m;
        }
        public void run() {
            String name = Thread.currentThread().getName();
            synchronized (msg) {
                try{
                    System.out.println(name + " acquired lock to msg object. waiting to get notified");
                    msg.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(name + " waiter done at time: " + System.currentTimeMillis());
            }
            System.out.println(name + " waiter giving up msg object lock");
        }
    }

    public class Notifier implements Runnable {      
        private Message msg;         
        public Notifier(Message msg) {
            this.msg = msg;
        }
        public void run() {
            String name = Thread.currentThread().getName();
            System.out.println(name + " started");
            try {
                Thread.sleep(5000);
                synchronized (msg) {
                    String localMesg = name + " acquired lock to msg object. Notifier work done.";
                    System.out.println(localMesg);
                    msg.setMsg(localMesg);
                    msg.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }    
        }    
    }

    void runtest() {
        Message msg = new Message("process it");
        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1,"waiter1").start();

        Waiter waiter2 = new Waiter(msg);
        new Thread(waiter2, "waiter2").start();

        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        System.out.println("All the threads are started");
    }

    public static void main(String [] args) {
        new ThreadTester().runtest();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

waiter1 acquired lock to msg object. waiting to get notified
waiter2 acquired lock to msg object. waiting to get notified
All the threads are started
notifier started
notifier acquired lock to msg object. Notifier work done.
waiter1 waiter done at time: 1419745413721
waiter1 waiter giving up msg object lock
Run Code Online (Sandbox Code Playgroud)

现在的问题是,当线程仍然持有时,如何waiter2notifier线程获取msg对象的锁waiter1?这似乎与我上面引用的Java教科书声明直接相矛盾.我错过了什么?

谢谢你的帮助.

小智 6

在模式中

synchronized (msg) {
  msg.wait();
}
Run Code Online (Sandbox Code Playgroud)

锁定msg确实是由synchronized声明采取的.但是该msg.wait()呼叫暂时释放锁并等待通知.一个以后msg.notify()或者msg.notifyAll()可以满足那个等待.等待结束后,msg再次锁定.在Notifier线程的示例中msg.notify(),这意味着两个Waiter线程中的一个msg.wait()可以满足它.这不会立即发生,因为msg.notify()它位于一个synchronized (msg)块内,因此通告程序线程正在保持锁定msg.但是一旦该块退出,无论哪个线程msg.wait()获得通知都将取回锁定msg并继续.

这种模式相当脆弱.通告程序线程通过执行5秒睡眠启动,以确保两个服务器线程各自到达它们msg.wait().如果没有睡眠,Notifier可以msg.notify()在Waiter线程完成之前完成msg.wait(),并且msg.notify()没有效果.由于这样的问题,通常最好使用同步类,例如Semaphorejava.util.concurrent包中使用,而不是使用synchronizedwait/ notify.