Java等待线程在通知后不会恢复

时间:2017-06-09 08:55:06

标签: java multithreading wait notify

我有以下程序有2个线程T1和T2。 T1首先运行并进入等待状态。 T2正在呼叫通知。为什么T1线程不会恢复并打印“Thread-0被唤醒”

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

请注意,此输出后我的程序不会结束/终止。任何人都可以解释为什么我的程序没有终止。

6 个答案:

答案 0 :(得分:2)

你的代码中有两个问题 1.您应该使用相同的对象在线程之间进行通信。 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();
        }
    }

答案 1 :(得分:1)

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

在t1中,这将引用在那里创建的匿名类的Object。

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

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

答案 2 :(得分:1)

问题是您没有在同一个对象上进行同步。尝试在每个线程中打印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();
    }
}

答案 3 :(得分:1)

您没有正确使用waitnotify

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

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()

答案 4 :(得分:1)

我同意你在错误对象上同步的其他答案。

我建议"在监视器中思考"。监视器是限制并发访问以保留内部合作状态的对象。因此,监视器可以清楚地确保同步,并且不会在任何单个线程中遍布整个位置。线程不应该彼此同步,它们应该通过它们尝试访问的资源进行同步。

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();

    }

}

答案 5 :(得分:1)

除了锁定不同对象的事实(由他人提及)之外,您的代码中还有另一个问题。你使用Thread.sleep来确保等待线程在其他调用notify之前开始等待,但你仍然没有猜测它不会发生反过来,使得等待线程永远等待。

你必须在while循环中使用一些'condition variable'才能安全起见。

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