一,問題描述
假設有兩個線程在並發運行,一個線程執行的代碼中含有一個死循環如:while(true)....當該線程在執行while(true)中代碼時,另一個線程會有機會執行嗎?
二,示例代碼(代碼來源於互聯網)
1 public class Service { 2 Object object1 = new Object(); 3 4 public void methodA() { 5 synchronized (object1) { 6 System.out.println("methodA begin"); 7 boolean isContinueRun = true; 8 //在這里執行一個死循環 9 while (isContinueRun) { 10 11 } 12 System.out.println("methodA end"); 13 } 14 } 15 16 Object object2 = new Object(); 17 18 public void methodB() { 19 synchronized (object2) { 20 System.out.println("methodB begin"); 21 System.out.println("methodB end"); 22 } 23 } 24 }
兩個線程類的實現如下:
1 import service.Service; 2 3 public class ThreadA extends Thread { 4 5 private Service service; 6 7 public ThreadA(Service service) { 8 super(); 9 this.service = service; 10 } 11 12 @Override 13 public void run() { 14 service.methodA(); 15 } 16 17 }
線程A執行methodA(),methodA()中有一個死循環
1 import service.Service; 2 3 public class ThreadB extends Thread { 4 5 private Service service; 6 7 public ThreadB(Service service) { 8 super(); 9 this.service = service; 10 } 11 12 @Override 13 public void run() { 14 service.methodB(); 15 } 16 17 }
線程B執行methodB(),當線程A進入methodA()中的while死循環時,線程B的能不能執行完成?
測試類
1 import service.Service; 2 import extthread.ThreadA; 3 import extthread.ThreadB; 4 5 public class Run { 6 7 public static void main(String[] args) { 8 Service service = new Service(); 9 10 ThreadA athread = new ThreadA(service); 11 athread.start(); 12 13 ThreadB bthread = new ThreadB(service); 14 bthread.start(); 15 } 16 17 }
執行結果:
由於線程A和線程B獲得的對象鎖不是同一把鎖,從結果中可以看出,線程B是可以執行完成的。而線程A由於進入了while死循環,故線程A一直執行運行下去了(整個程序未結束),但線程B會結束。
也就是說,盡管線程A一直在while中執行,需要占用CPU。但是,線程的調度是由JVM或者說是操作系統來負責的,並不是說線程A一直在while循環,然后線程B就占用不到CPU了。對於線程A而言,它就相當於一個“計算密集型”作業了。如果我們的while循環是不斷地測試某個條件是否成立,那么這種方式就很浪費CPU,可參考一個具體的實例:JAVA多線程之線程間的通信方式 中的“線程間的通信方式”第二點while輪詢。
如果把Service.java修改成如下:
1 public class Service { 2 // Object object1 = new Object(); 3 4 public void methodA() { 5 synchronized (this) { 6 System.out.println("methodA begin"); 7 boolean isContinueRun = true; 8 //在這里執行一個死循環 9 while (isContinueRun) { 10 11 } 12 System.out.println("methodA end"); 13 } 14 } 15 16 // Object object2 = new Object(); 17 18 public void methodB() { 19 synchronized (this) { 20 System.out.println("methodB begin"); 21 System.out.println("methodB end"); 22 } 23 } 24 }
若線程A先獲得對象鎖時,由於while循環,線程A一直在while空循環中。而線程B也因為無法獲得鎖而執行不了methodB()。
可以看出,如果在一個線程在synchronized方法中無法退出,無法將鎖釋放,另一個線程就只能無限等待了。