Java 通知后等待线程没有恢复

Java waiting Thread doesn't resume after notify

我下面的程序有 2 个线程 T1 和 T2。 T1先是运行,进入waiting状态。 T2 正在调用通知。为什么 T1 线程不恢复并打印 "Thread-0 is waken up"

public class WaitNotifyTest{
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    try {
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + " is running");
                        notify();
                        System.out.println(Thread.currentThread().getName() + " notifying");
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

输出为

Thread-0 is running
Thread-1 is running
Thread-1 notifying

注意在这个输出之后我的程序没有 ends/terminate。谁能解释一下为什么我的程序没有终止。

我认为这是因为 synchronized (this) 被用于锁定目的。

在 t1 中,这将引用在那里创建的匿名 class 的对象。

在 t2 中,这将引用在那里创建的另一个匿名 class 的对象。简单来说,两者所指的对象不同。

为了wait-notify工作,您必须锁定同一对象。

问题是您没有在同一个对象上进行同步。尝试在每个线程中打印 this 以进行验证。然后尝试在同一对象上同步,对该锁调用 waitnotify(否则您将无法获得正确的响应)。

   public class WaitNotifyTest{
    public static void main(String[] args) {
        Integer someObject = 2;
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 this = " + this);
                synchronized (someObject) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        someObject.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t2 this = " + this);
                synchronized (someObject) {
                    try {
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + " is running");
                        someObject.notify();
                        System.out.println(Thread.currentThread().getName() + " notifying");
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

您没有正确使用 waitnotify

您必须在同一个对象上进行同步,以便线程能够相互等待通知。 您可以在它们之间共享一个对象,并使用与监视器相同的共享 Object 使用同步块调用 waitnotify。以下解决了问题:

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

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + " is running");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " is waken up");
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (obj) {
                try {
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + " is running");
                    obj.notify();
                    System.out.println(Thread.currentThread().getName() + " notifying");
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }
    });
    t1.start();
    t2.start();
}

请注意 synchronized (this) 现在是 synchronized (obj) 等一下,waitnotify 不是 obj.wait()obj.notify()

您的代码中存在两个问题 1.You 应该使用相同的对象在线程之间进行通信。 2.call 等待并通知您已锁定的同一对象。

public class WaitNotifyTest{


    public static void main(String[] args) {
        Object lock=new Object(); 
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + " is running");
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " is waken up");
                    }
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        try {
                            Thread.sleep(3000);
                            System.out.println(Thread.currentThread().getName() + " is running");
                            lock.notify();
                            System.out.println(Thread.currentThread().getName() + " notifying");
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            });
            t1.start();
            t2.start();
        }
    }

我同意您同步错误对象的其他答案。

我建议"think in monitors"。监视器是限制并发访问以保持内部一致状态的对象。因此,同步显然是由监视器确保的,并且不会在任何单个线程中遍布整个地方。线程不应相互同步,它们应该由它们尝试访问的资源同步。

public class Main {


    private static class Monitor {

        public synchronized void operation1() {
            System.out.println(Thread.currentThread().getName() + " is running");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " is waken up");
        }


        public synchronized void operation2() {
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() + " is running");
                notify();
                System.out.println(Thread.currentThread().getName() + " notifying");
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }

    }


    public static void main(String[] args) {

        Monitor monitor = new Monitor();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation1();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation2();
            }
        });

        t1.start();
        t2.start();

    }

}

除了您锁定不同对象这一事实(其他人提到)之外,您的代码中还有另一个问题。您使用 Thread.sleep 来确保等待线程在其他调用 notify 之前开始等待,但您仍然没有保证它不会以相反的方式发生,从而使等待线程永远等待。

为了安全起见,您还必须在 while 循环中使用一些 'condition variable'。

阅读 oracle's docs 以获取示例和进一步说明。