Java线程通信——wait() 和 notify()

  Object类中有关线程通信的方法有两个notify方法和三个wait方法,官方解释:

void notify()
Wakes up a single thread that is waiting on this object‘s monitor.
void notifyAll()
Wakes up all threads that are waiting on this object‘s monitor.
String toString()
Returns a string representation of the object.
void wait()
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
void wait(long timeout)
Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
void wait(long timeout, int nanos)
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

  这些方法都是final类型的,不能被子类重写。

  调用wait()和notify()方法的前提是,线程调用这两个方法时,拥有当前对象的monitor,即锁。所以,这两种方法的调用必须放在synchronized方法或synchronized块中。

  wait()与sleep()的比较:调用wait()后,当前线程失去了对象的monitor,必须被其他线程唤醒或设定的等待时间已超时,才能继续执行,并且被唤醒后,该线程并不会马上继续运行,而是放在线程就绪队列中,与其他线程公平竞争,获取对象的monitor。调用sleep()后,当前线程仍用够对象的monitor,当设定的睡眠时间超时后,线程会马上继续执行。

  一个线程变为一个对象的锁的拥有者,可以通过三种途径:

    1. 运行这个对象的synchronized的实例方法。
    2. 运行这个对象的synchronized的语句块。
    3. 对于Class类的对象,运行类的synchronized、static的方法。

假设有两个线程A和B公用一个NumberControl的类的对象,类结构如下:

Java线程通信——wait() 和 notify()
public class NumberControl
{
    private int number;

    public synchronized void increase()
    {
        if (0 != number)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(number);
        notify();
    }

    public synchronized void decrease()
    {
        if (0 == number)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        number--;
        System.out.println(number);
        notify();
    }
}
NumberControl

  A线程执行对象的increase()方法,如果number为1,则线程等待。B线程执行对象的decrease()方法,如果number为0,则线程等待。然后执行A、B线程,得到的结果,number回程1、0、1、0的交替变化。

  但需要注意的是,如果在添加更过的线程共享这个对象,假设是4个线程A、B、C、D,A和C线程调用increase()方法,B和D线程调用decrease方法,再去试图让number得到1、0的交替变化,那当线程被唤醒后,仍需判断number的状态,是1还是0,因为在同一个对象中,当一个线程执行notify()时,被唤醒的线程是被随机挑选出来的。可能出现的情况是,B、C、D线程都处于等待状态,A状态执行完notify()方法,此时number是1,B、C、D其中任意一个都有可能被唤醒,如果C被唤醒,但C没有再去判断number的状态,那C将继续去执行,则number会继续增加,变为2,出现了不需要的结果。所以在判断语句中,不要使用if(),而是使用while()语句来判断number的状态,这样就可以避免异常状态的出现。

void notify()
Wakes up a single thread that is waiting on this object‘s monitor.
void notifyAll()
Wakes up all threads that are waiting on this object‘s monitor.

Java线程通信——wait() 和 notify(),布布扣,bubuko.com

Java线程通信——wait() 和 notify()

上一篇:WinForm 子线程修改主线程(UI线程)


下一篇:数据分组统计函数族——apply族用法与心得