通知和等待代码场景

Notify and wait code scenario

public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

此处显示输出:-

i=0in t1 
i=1in t4 
Thread-0is running 
Thread-1is notifying 
notified 

还应在输出中打印最后一行,即; “Thread-0 is waken up”。为什么在打印 "notified" 之后它不会松开对线程 "t1 run() method " 的锁定并继续执行 t1 中 wait() 之后的代码。即它应该在打印 "notified".

之后打印 "Thread-0 is waken up"

你的synchronized块有"no"效果。

您的 synchronized(this) 刚刚获得 Runnable 实例的锁,您还实现了 run 方法。

您的线程 t1 永远不会收到通知,它会等待您使用 wait() 方法的 Runnable 获得通知。唯一持有对此 Runnable 的引用的对象是 Thread 对象 t1 并且(通常)不会对该 Runnable 调用 notify()notifyAll()

我正在使用 int[] 来存储 int 值以及持有锁/监视器。解决方案只是向您展示如何做到这一点,并不意味着这样做是好的做法。

我建议阅读有关 Java 中的同步如何工作的很好的教程。

我修改了您的示例,使其按您预期的方式工作。

public class NotifyAndWaitExample2 {
    private static int[] i = {0};

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    if (i[0] <= 0) {
                        System.out.println("i=" + i[0] + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");
                        try {
                            i.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    i[0]++;
                    System.out.println("i=" + i[0] + "in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        i.notifyAll();
                        System.out.println("notifying");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

您正在锁定两个不同的对象。在您的示例中, "this" 指的是每个可运行实例。除此之外,变量"i"必须是volatile的(否则不同线程看不到最新的变化)

见下文:

public class NotifyAndWaitExample {

    private volatile int i = 0;
    private Object lock1 = new Object();

    public static void main(String[] args) {
        NotifyAndWaitExample notifyAndWaitExample = new NotifyAndWaitExample();
        notifyAndWaitExample.execute();
    }

    private void execute() {


        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    if (i <= 0) {
                        System.out.println("i= " + i + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");

                        try {
                            lock1.wait();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });

        Thread t4 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    i++;
                    System.out.println("i= " + i + " in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        lock1.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });


        t1.start();
        t4.start();
    }

}
public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Object lock = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        lock.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

您当前的问题是您同步了错误的(不同的)对象。正如您在代码中所说 "synchronized(this)" "this" 是当前线程实例。因为你有两个同步不会发生。

我真的建议用显示器思考。监视器是一种资源包装器,它以一种保持内部状态一致性的方式限制并发访问。我重新编写了您的代码以使用监视器。

public class NotifyAndWaitExample2 {

    private static class Monitor {

        // Resource
        private int i;


        public synchronized void operation1() {

            if (i <= 0) {
                System.out.println("i=" + i + "in t1");
                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() {

            i++;
            System.out.println("i=" + i + "in t4");
            System.out.println(Thread.currentThread().getName() + "is notifying");
            try {
                Thread.sleep(1000);
                notify();
                System.out.println("notified");
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation2();
            }
        });

        t1.start();
        t4.start();

    }
}

"wait()" 和 "notify()" 现在在同一个对象上执行,因此执行线程将同步。