📜  Javawait()和notify()的区别

📅  最后修改于: 2021-09-14 01:20:27             🧑  作者: Mango

wait()notify()是 Object 类的方法。它们被引入与轮询分道扬镳,轮询是反复检查要满足的条件的过程。轮询会大量浪费 CPU 资源,因此不是首选。

wait() 有 3 个变体:

1.不带任何参数的基础版

public final void wait()
// will cause thread to wait till notify is called

2.采用单个超时参数的版本

public final void wait(long timeout)
// will cause thread to wait either till notify is called or 
// till timeout (One which occurs earlier)

3.版本采用超时参数以及纳秒参数以获得额外精度

public final void wait(long timeout,
int nanoseconds)

notify() 有 1 个签名

public final void notify()
// Function does not take any argument

Wait() notify()
When wait() is called on a thread holding the monitor lock, it surrenders the monitor lock and enters the waiting state. When the notify() is called on a thread holding the monitor lock, it symbolizes that the thread is soon going to surrender the lock.
There can be multiple threads in the waiting state at a time.

One of the waiting threads is randomly selected and notified about the same. The notified thread then exits the waiting state and enters the blocked state where it waits till the previous thread has given up the lock and this thread has acquired it. Once it acquires the lock, it enters the runnable state where it waits for CPU time and then it starts running.

下面是 wait() 和 notify() 方法的演示:

Java
// Java Program to demonstrate usage of wait() and notify()
  
class demo {
    // variable to check if part1 has returned
    // volatile used to prevent threads from
    // storing local copies of variable
    volatile boolean part1done = false;
  
    // method synchronized on this
    // i.e. current object of demo
    synchronized void part1()
    {
        System.out.println("Welcome to India");
        part1done = true;
        System.out.println(
            "Thread t1 about to surrender lock");
        // notify the waiting thread, if any
        notify();
    }
  
    // method synchronized on this
    // i.e. current object of demo
    synchronized void part2()
    {
        // loop to prevent spurious wake-up
        while (!part1done) {
            try {
                System.out.println("Thread t2 waiting");
                // wait till notify is called
                wait();
                System.out.println(
                    "Thread t2 running again");
            }
            catch (Exception e) {
                System.out.println(e.getClass());
            }
        }
        System.out.println("Do visit Taj Mahal");
    }
}
  
public class Main {
  
    public static void main(String[] args)
    {
  
        // Make an instance of demo calss
        demo obj = new demo();
  
        // Thread t1 will call part1()
        Thread t1 = new Thread(new Runnable() {
            public void run() { obj.part1(); }
        });
  
        // Thread t2 will call part2()
        Thread t2 = new Thread(new Runnable() {
            public void run() { obj.part2(); }
        });
  
        // Start t2 and then t1
        t2.start();
        t1.start();
    }
}


Java
// Program demonstrating occurance of InterruptedException
  
class demo {
    volatile boolean part1done = false;
  
    synchronized void part1()
    {
        System.out.println("Welcome to India");
        part1done = true;
        // notify() has been commented, waiting
        // thread remains waiting forever notify();
    }
  
    synchronized void part2()
    {
        while (!part1done) {
            try {
                wait();
            }
            catch (Exception e) {
                System.out.println("Exception : "
                                   + e.getClass());
                // quit program after exception is thrown
                System.exit(-1);
            }
        }
        System.out.println("Do visit Taj Mahal");
    }
}
  
public class Main {
  
    public static void main(String[] args)
    {
        // Make an instance of demo class
        demo obj = new demo();
  
        // Thread t1 will call part1()
        Thread t1 = new Thread(new Runnable() {
            public void run() { obj.part1(); }
        });
  
        // Thread t2 will call part2()
        Thread t2 = new Thread(new Runnable() {
            public void run() { obj.part2(); }
        });
  
        // Start t2 and then t1
        t2.start();
        t1.start();
  
        // This is a counter which will
        // interrupt Thread t2 after 3 seconds
        long startTime = System.currentTimeMillis();
        while (true) {
            if (System.currentTimeMillis() - startTime
                > 3000)
                t2.interrupt();
        }
    }
}


Java
// Program to demonstrate IllegalMonitorStateException
  
class demo {
    volatile boolean part1done = false;
    // Made an Integer object a
    // and set it randomly to 5
    Integer a = 5;
  
    void part1()
    {
        // Synchronized code on a
        synchronized (a)
        {
            System.out.println("Welcome to India");
            part1done = true;
            // calling this.notify()
            notify();
        }
    }
  
    void part2()
    {
        // Synchronized code on a
        synchronized (a)
        {
            while (!part1done) {
                try {
                    // calling this.wait()
                    wait();
                }
                catch (Exception e) {
                    System.out.println("Exception: "+e.getClass());
                    System.exit(-1);
                }
            }
            System.out.println("Do visit Taj Mahal");
        }
    }
}
  
public class Main {
  
    public static void main(String[] args)
    {
  
        // Make an instance of demo class
        demo obj = new demo();
  
        // Thread t1 will call part1()
        Thread t1 = new Thread(new Runnable() {
            public void run() { obj.part1(); }
        });
  
        // Thread t2 will call part2()
        Thread t2 = new Thread(new Runnable() {
            public void run() { obj.part2(); }
        });
  
        // Start t2 and then t1
        t2.start();
        t1.start();
    }
}


输出
Thread t2 waiting
Welcome to India
Thread t1 about to surrender lock
Thread t2 running again
Do visit Taj Mahal

各种异常

A.等待()

  • 必须将 wait() 包含在 try-catch 块中,因为如果处于等待状态的线程被中断,则会抛出 InterruptedException。
  • 如果超时值为负或纳秒值不在 0 到 9,99,999 的范围内,则等待住房参数的其他两种变体将抛出 IllegalArgumentException。

下面是异常处理的实现。

Java

// Program demonstrating occurance of InterruptedException
  
class demo {
    volatile boolean part1done = false;
  
    synchronized void part1()
    {
        System.out.println("Welcome to India");
        part1done = true;
        // notify() has been commented, waiting
        // thread remains waiting forever notify();
    }
  
    synchronized void part2()
    {
        while (!part1done) {
            try {
                wait();
            }
            catch (Exception e) {
                System.out.println("Exception : "
                                   + e.getClass());
                // quit program after exception is thrown
                System.exit(-1);
            }
        }
        System.out.println("Do visit Taj Mahal");
    }
}
  
public class Main {
  
    public static void main(String[] args)
    {
        // Make an instance of demo class
        demo obj = new demo();
  
        // Thread t1 will call part1()
        Thread t1 = new Thread(new Runnable() {
            public void run() { obj.part1(); }
        });
  
        // Thread t2 will call part2()
        Thread t2 = new Thread(new Runnable() {
            public void run() { obj.part2(); }
        });
  
        // Start t2 and then t1
        t2.start();
        t1.start();
  
        // This is a counter which will
        // interrupt Thread t2 after 3 seconds
        long startTime = System.currentTimeMillis();
        while (true) {
            if (System.currentTimeMillis() - startTime
                > 3000)
                t2.interrupt();
        }
    }
}
输出
Welcome to India
Exception : class java.lang.InterruptedException

B.通知()

与 wait() 不同,notify 方法不会抛出 InterruptedException,因此不需要将它放在 try-catch 块中

笔记:

  • wait() 和 notify() 都有抛出 IllegalMonitorStateException 的倾向
  • 当线程持有对象 A 的监视器锁并尝试调用对象 B 上的等待或通知时,就会发生这种情况。
  • 在前面的所有示例中,方法都是在“this”上同步的,即用于调用这些方法的对象 (obj)。此外,wait() 和 notify() 被称为 this.wait() 和 this.notify() (使用 this 是多余的)。因此,没有问题。
  • 在下面的示例中,方法 part1 和 part2 现在在一个 Integer 对象上同步,但 wait() 和 notify() 仍在调用这些方法 (obj) 的对象上调用。
  • 这会导致 IllegalMonitorStateException

下面是异常处理的实现。

Java

// Program to demonstrate IllegalMonitorStateException
  
class demo {
    volatile boolean part1done = false;
    // Made an Integer object a
    // and set it randomly to 5
    Integer a = 5;
  
    void part1()
    {
        // Synchronized code on a
        synchronized (a)
        {
            System.out.println("Welcome to India");
            part1done = true;
            // calling this.notify()
            notify();
        }
    }
  
    void part2()
    {
        // Synchronized code on a
        synchronized (a)
        {
            while (!part1done) {
                try {
                    // calling this.wait()
                    wait();
                }
                catch (Exception e) {
                    System.out.println("Exception: "+e.getClass());
                    System.exit(-1);
                }
            }
            System.out.println("Do visit Taj Mahal");
        }
    }
}
  
public class Main {
  
    public static void main(String[] args)
    {
  
        // Make an instance of demo class
        demo obj = new demo();
  
        // Thread t1 will call part1()
        Thread t1 = new Thread(new Runnable() {
            public void run() { obj.part1(); }
        });
  
        // Thread t2 will call part2()
        Thread t2 = new Thread(new Runnable() {
            public void run() { obj.part2(); }
        });
  
        // Start t2 and then t1
        t2.start();
        t1.start();
    }
}
输出
Exception: class java.lang.IllegalMonitorStateException

要修复上面的代码,只需将第 19 行的 notify() 替换为 a.notify(),并将第 31 行的 wait() 替换为 a.wait()。