一、重要方法概覽
類 | 方法名 | 說明 |
---|---|---|
Thread | sleep() | 讓線程等待 |
join() | 等待其他線程執行完畢 | |
yield() | 放棄已經獲取到的CPU資源 | |
currentThread() | 獲取當前執行線程的引用 | |
start()、run() | 啓動線程 | |
interrtupt() | 中斷線程 | |
stop()、suspend()、resuem() | 已廢棄 | |
Object | wait()、notify()、notifyAll() | 讓線程暫時休息和喚醒 |
二、Object類中的wait()、notify()、notifyAll()
1.作用
- 阻塞階段
執行wait()後,線程進入阻塞狀態,wait()需要在synchronized的方法中使用。 - 喚醒階段
notify()會喚醒某個正在等待鎖的線程,如果有多個線程都在等待鎖,則會選取其中任意一個喚醒。需要在synchronized的方法中使用
notifyAll()會把所有正在等待的線程全部喚醒,最終哪個線程能獲得鎖,由操作系統決定。 - 遇到中斷
線程在阻塞狀態,如果被中斷了,則該線程會拋出中斷異常並釋放鎖。
2.wait()和notify()的演示
/**
* Object類中的wait()、notify()的基本用法
*/
public class ThreadWaitNotify {
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new DoWork1());
Thread thread2 = new Thread(new DoWork2());
thread1.start();
Thread.sleep(1000);
thread2.start();
}
}
class DoWork1 implements Runnable{
@Override
public void run() {
synchronized (ThreadWaitNotify.object){
System.out.println("線程1開始執行");
try {
// 釋放鎖,阻塞
ThreadWaitNotify.object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程1重新獲得鎖");
}
}
}
class DoWork2 implements Runnable{
@Override
public void run() {
synchronized (ThreadWaitNotify.object){
ThreadWaitNotify.object.notify();
System.out.println("線程2調用notify()");
}
}
}
線程1中執行了wait()語句後即線程1進入等待狀態,並且釋放掉了鎖,否則線程2無法進入synchronized的代碼塊。
3.notify()和notifyAll()的演示
/**
* Object類中的notify()、notifyAll()的基本用法
* 線程1、線程2阻塞,線程3負責喚醒他們
*/
public class ThreadWaitNotify {
public static Object resource = new Object();
public static void main(String[] args) throws InterruptedException {
DoWork1 doWork = new DoWork1();
DoWork3 doWork3 = new DoWork3();
Thread thread1 = new Thread(doWork);
Thread thread2 = new Thread(doWork);
Thread thread3 = new Thread(doWork3);
thread1.start();
thread2.start();
Thread.sleep(100);
thread3.start();
}
}
class DoWork1 implements Runnable{
@Override
public void run() {
synchronized (ThreadWaitNotify.resource){
System.out.println("線程["+Thread.currentThread().getName()+"]獲得鎖開始執行");
try {
// 釋放鎖,阻塞
System.out.println("線程["+Thread.currentThread().getName()+"]wait阻塞釋放鎖");
ThreadWaitNotify.resource.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程["+Thread.currentThread().getName()+"]重新獲得鎖");
}
}
}
class DoWork3 implements Runnable{
@Override
public void run() {
synchronized (ThreadWaitNotify.resource){
ThreadWaitNotify.resource.notifyAll();
System.out.println("線程["+Thread.currentThread().getName()+"]調用notify()");
}
}
}
如果把notifyAll()換成notify()呢?
線程0和線程1都在阻塞,而線程2只選擇喚醒一個,那麼應該剩餘一個線程永遠在阻塞了。
class DoWork3 implements Runnable{
@Override
public void run() {
synchronized (ThreadWaitNotify.resource){
ThreadWaitNotify.resource.notify();
System.out.println("線程["+Thread.currentThread().getName()+"]調用notify()喚醒一個線程");
}
}
}