wait() 和 notify()

2019-08-03  本文已影响0人  gczxbb

一、阻塞和恢复

  • Thread#sleep方法
  • 阻塞式IO方法
  • 获取同步锁失败,(锁被其他线程占用)
  • Object#wait方法。
  • sleep到达时间
  • 阻塞方法返回
  • 成功获取锁
  • Object#nofity方法

二、wait()与notify()方法

sleep()方法,Thread类,静态方法,线程休眠指定时间(参数)。
wait()方法,Object类,对象方法,本线程休眠。

public class WaitNotifyRunnable implements Runnable {
    public static final String TAG = "WaitNotifyRunnable";

    public void secondMethod() throws Exception {
        String threadName = Thread.currentThread().getName();
        Thread.sleep(2000);//
        Log.d(TAG, threadName + "线程:secondMethod()方法");
        synchronized (this) {
            Log.d(TAG, threadName + "线程,竞争获得锁,进入休眠" );
            Thread.sleep(10000);//不会释放锁
            Log.d(TAG, threadName + "线程,通知唤醒wait线程" );
            notifyAll();
            Thread.sleep(5000);//不会释放锁
        }
    }

    public void run() {
        try {
            String threadName = Thread.currentThread().getName();
            Log.d(TAG, threadName + "线程:run()方法");
            synchronized (this) {
                Log.d(TAG, threadName + "线程,竞争获得锁,进入休眠" );
                this.wait();//释放锁。
                Log.d(TAG, threadName+"线程,被唤醒" );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

第一个是run方法,第二个方法外部线程调用,示例中共启动四个线程,并发执行。
wait()方法必须在同步代码中,sleep()方法可以在任何地方。

//wait_notify
public static void startWaitNotify() {
    //线程1
    final WaitNotifyRunnable taskRunnable = new WaitNotifyRunnable();
    Thread thread = new Thread(taskRunnable);
    thread.start();
    Thread thread2 = new Thread(taskRunnable);
    thread2.start();
    Thread thread3 = new Thread(taskRunnable);
    thread3.start();

    //线程4
    Thread second = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                taskRunnable.secondMethod();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    second.start();
}

前三个线程并发执行任务,run方法,每一个进入synchronized()的线程对Runnable对象加锁。
wait方法,线程进入休眠,同时释放锁,三个并发线程轮流竞争到锁进入同步代码块并wait()休眠。
第四个线程执行任务的secondMethod方法,和前三个线程是同一个对象锁。先执行2s休眠。
前三个线程的wait()方法会释放锁,当第四个线程获得锁,sleep方法,不会释放锁。sleep()方法,时间自动唤醒,不需要notify通知唤醒。
当第四个线程执行nofity()方法,唤醒其中一个wait()方法休眠的线程,线程四继续休眠,未释放锁,此时,被唤醒线程需要等待锁。再等待sleep(5000)5s,释放锁,竞争获取锁继续执行。

20225-20273/com.gc.multi D/WaitNotifyRunnable: Thread-2线程,竞争获得锁,进入休眠
20225-20274/com.gc.multi D/WaitNotifyRunnable: Thread-3线程,竞争获得锁,进入休眠
20225-20275/com.gc.multi D/WaitNotifyRunnable: Thread-4线程,竞争获得锁,进入休眠

//第四个线程获得锁
20225-20276/com.gc.multi D/WaitNotifyRunnable: Thread-5线程,竞争获得锁,进入休眠
20225-20276/com.gc.multi D/WaitNotifyRunnable: Thread-5线程,sleep结束,通知唤醒wait线程
20225-20276/com.gc.multi D/WaitNotifyRunnable: Thread-5线程,即将再次sleep,不会释放锁,被唤醒的wait,进入锁等待池

//第四个线程notify通知唤醒,sleep未释放锁,继续休眠后释放。
20225-20274/com.gc.multi D/WaitNotifyRunnable: Thread-3线程,被唤醒
20225-20273/com.gc.multi D/WaitNotifyRunnable: Thread-2线程,被唤醒
20225-20275/com.gc.multi D/WaitNotifyRunnable: Thread-4线程,被唤醒

nofity()方法,仅唤醒一个wait()方法的休眠线程。nofityAll()方法,唤醒所有wait()线程。

三、join()与yield()方法

join()方法,在一个线程A中调用另一个线程B的join()方法,A线程将等待B线程执行完毕再执行。
yield()方法,当线程执行了该方法,是线程从运行状态转换就绪状态,把运行机会交给其他具有相同优先级的线程,不是阻塞,出让cpu后,该线程再一次轮转仍然有可能被cpu选中执行。

四、总结

sleep方法,Thread类的静态方法,wait方法,Object对象的方法。

wait方法只能在同步代码块或同步方法,sleep方法使用在任何地方。

两个方法都会使当前线程让出CPU,wait方法会释放对象锁,sleep方法不会。

sleep方法在到达时间时,自动唤醒,wait需要notify通知唤醒,进入对象锁定池,再次获得对象锁才能继续执行。

线程的interrupt()方法会打断休眠状态(wait和sleep),抛出InterruptedException异常。


任重而道远

上一篇下一篇

猜你喜欢

热点阅读