簡述
這兩個操作就好比播放器的暫停和恢復。
但這兩個 API 是過期的,也就是不建議使用的。
不推薦使用 suspend() 去掛起線程的原因,是因為 suspend() 在導致線程暫停的同時,並不會去釋放任何鎖資源。其他線程都無法訪問被它占用的鎖。直到對應的線程執行 resume() 方法后,被掛起的線程才能繼續,從而其它被阻塞在這個鎖的線程才可以繼續執行。
但是,如果 resume() 操作出現在 suspend() 之前執行,那么線程將一直處於掛起狀態,同時一直占用鎖,這就產生了死鎖。而且,對於被掛起的線程,它的線程狀態居然還是 Runnable。
實例
1 import java.util.concurrent.locks.LockSupport; 2 /** 3 * Created by zhengbinMac on 2017/3/3. 4 */ 5 public class SuspendResumeTest { 6 public static Object object = new Object(); 7 static TestThread t1 = new TestThread("線程1"); 8 static TestThread t2 = new TestThread("線程2"); 9 public static class TestThread extends Thread{ 10 public TestThread(String name) { 11 super.setName(name); 12 } 13 @Override 14 public void run() { 15 synchronized (object) { 16 System.out.println(getName()+" 占用。。"); 17 Thread.currentThread().suspend(); 18 // LockSupport.park(); 19 } 20 } 21 } 22 public static void main(String[] args) throws InterruptedException { 23 t1.start(); 24 Thread.sleep(200); 25 t2.start(); 26 t1.resume(); 27 // LockSupport.unpark(t1); 28 // LockSupport.unpark(t2); 29 t2.resume(); 30 t1.join(); 31 t2.join(); 32 } 33 }
運行多次,可能出現下圖結果:
代碼執行流程,如下圖所示:
此時,通過 jps 和 jstack 命令,來觀察線程狀態,如下圖所示:
從輸出結果來看,線程 t2 其實是被掛起的,但是從上圖來看,它的線程狀態卻是 RUNNABLE,這會使我們誤判當前系統狀態。
參考資料
[1] 實戰Java高並發程序設計, 2.2.5 - 掛起(suspend)和繼續執行(resume)線程
[2] Java並發編程的藝術, 4.2.4 - 過期的suspend()、resume() 和 stop()