调用Java Object的wait()会中断线程同步

sof*_*sof 5 java concurrency multithreading

public class Main2 {
    public static void main(String[] args) {
        new Test2().start();
        new Test2().start();
    }
}

class Test2 extends Thread {
    @Override
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

作为运行测试的实际结果:从两个线程开始等待,开始等待,两次.与预期结果相比:开始等待,从两个线程之一只有一次,因为在synchronized run()方法中调用了wait().为什么可以调用Object的wait()中断线程同步?

吃了很多!


    public class Main3 {

    public static void main(String[] args) {
        Test3 t = new Test3();
        new Thread(t).start();
        new Thread(t).start();
    }
}

class Test3 implements Runnable {
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

@akf和@Sean Owen

谢谢你的回复.对不起我的错误,现在我修改了代码以将同步放在同一个对象的run()上,结果仍然是:开始等待,开始等待,两次.

@akf

wait将释放同步已抓取的锁,并在通知线程后重新获取.

你能详细说一下吗?

akf*_*akf 10

  1. 在此示例中您正在同步的对象不是类,而是实例,因此每个新Test2对象将在不同的监视器上进行同步.
  2. 你可能在这里寻找的方法sleep不是wait. wait将释放synchronized已抓取的锁,并在通知线程后重新获取.

请注意,要使测试正常工作,您需要锁定一个公共对象.如果你想看到wait实际操作,我已经把一个简单的应用程序放在一起,它将弹出一个带有"通知"按钮的框架.将启动两个线程,等待一个公共对象,并在按下按钮时通知.

public static void main(String[] args)
{
    final Object lock = new Object(); 

    final JFrame frame = new JFrame("Notify Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton button = new JButton("Notify");
    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent evt) {
            synchronized(lock) {
                lock.notify();
            }
        }
    });
    frame.add(button);

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            frame.setVisible( true );
        }
    });

    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("1. starting");
                    lock.wait();
                    System.out.println("1. step 1");
                    lock.wait();
                    System.out.println("1. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();
    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("2. starting");
                    lock.wait();
                    System.out.println("2. step 1");
                    lock.wait();
                    System.out.println("2. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();

}
Run Code Online (Sandbox Code Playgroud)

对于简单的解释wait,JavaDoc始终是一个好的开始:

导致当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法.换句话说,此方法的行为就像它只是执行调用wait(0)一样.

当前线程必须拥有此对象的监视器.线程释放此监视器的所有权并等待,直到另一个线程通过调用notify方法或notifyAll方法通知等待此对象监视器的线程唤醒.然后线程等待,直到它可以重新获得监视器的所有权并继续执行.


Sea*_*wen 3

您有两个不同的 Test2 对象。同步方法锁定对象。他们没有获取相同的锁,所以不应该打印两次。