【问题标题】:Understanding multi threading wait and notify [duplicate]了解多线程等待和通知[重复]
【发布时间】:2018-05-14 02:52:03
【问题描述】:

我正在学习多线程,并试图了解如何使用 Object 类的等待和通知方法。我已经通过这个链接https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example 并编写了以下程序

服务员

public class Waiter implements Runnable {
    private Message m;
    public Waiter(Message m) {
         this.m = m;
    }
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(t1 + " thread waiting for message");
        synchronized (m) {
            try {
                m.wait();
                System.out.println(t1 + " " + m.getText());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(t1 + " thread waiting for message");
    }
}

通知器

public class Notifier implements Runnable {
    private Message m;
    public Notifier(Message m) {
         this.m = m;
    }
    public void run() {
        synchronized (m) {
            try {
                Thread.sleep(2000);
                m.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试

public class WaitNotifyTest {
    public static void main(String[] str) {
        Message m = new Message("hello");
        new Thread(new Waiter(m), "t1").start();
        new Thread(new Waiter(m), "t2").start();
        new Thread(new Notifier(m)).start();
    }
}

当我执行程序时,它有时会正常终止,有时会无限期等待,有时其中一个线程终止,另一个线程无限期等待。谁能告诉我这里出了什么问题?

我还想知道一些实时应用等待和通知方法的例子。

【问题讨论】:

  • 我认为问题出在 Notifier 类的同步块中的 Thread.sleep(2000) 上。一旦我将它移到同步块之外,程序总是会正确终止。谁能告诉我这里有什么区别?
  • 假设Notifier线程首先运行,并进入synchronized (m)部分。 Waiter 线程无法进入此部分,直到 Notifier 离开它。但在离开时,m.notifyAll()已经执行。因此,当Waiter 进入该部分并执行m.wait() 时,它将等待永远:此后没有人会通知线程。通过将Thread.sleep(2000) 移动到该部分之外,您可以大大降低给定场景的可能性:虽然Notifier在关键部分之外 休眠,但Waiter 很有可能首先进入该部分。

标签: java multithreading


【解决方案1】:

当您在等待时,最佳做法是在带有条件的 while 循环中执行。可能存在线程会通知然后其他线程进入等待状态的情况。因此线程将始终处于等待状态

修改代码:

public class Waiter implements Runnable {
    private Message m;

    public Waiter(Message m) {
        this.m = m;
    }

    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " thread waiting for message");
        synchronized (m) {
            try {
                while (m.getText() == null) {
                    m.wait();
                }
                System.out.println(name + " " + m.getText());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name + " thread waiting for message");
    }
}

public class Notifier implements Runnable {
    private Message m;

    public Notifier(Message m) {
        this.m = m;
    }

    public void run() {
        synchronized (m) {

            m.setText("hello");
            m.notifyAll();

        }
    }
}

public class WaitNotifyTest {
    public static void main(String[] str) {
        Message m = new Message();
        new Thread(new Waiter(m), "t1").start();
        new Thread(new Waiter(m), "t2").start();
        new Thread(new Notifier(m)).start();
    }
}

【讨论】:

  • 当我将 Thread.sleep 移到同步块之外并且程序正确终止时。或者,我听从了你的建议,将 Thread.sleep 移回同步并添加了循环,程序正常终止。我无法理解在同步块内部和外部设置 Thread.sleep 有什么区别。
  • 当你使用线程睡眠时它总是暂停当前线程的执行并且线程睡眠不会丢失当前线程获得的任何监视器或锁。因此,在通知程序之后等待执行的可能性很高。
  • @gati sahu - 由于代码使用 notifyAll() 不会调用所有等待线程。此外,发布的代码对我来说也很好,不会阻塞。我能想到的唯一可能性是如果在线程的 wait() 之前处理了通知。
  • @gatisahu 很抱歉,我不明白。我是多线程的新手。我只有理论知识。能详细解释一下吗?
猜你喜欢
  • 2013-05-29
  • 1970-01-01
  • 2011-02-07
  • 1970-01-01
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多