一、阻塞和恢复
- 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异常。
任重而道远
网友评论