1.8暫停線程,1.8暫停
在java中,使用suspend()方法暫停線程,使用resume()方法恢複線程的執行。
1.8.1suspend與resume的使用:
線程代碼:
public class Thread1 extends Thread { private long i = 0L; public long getI() { return i; } public void setI(long i) { this.i = i; } @Override public void run() { while (true) { i++; } }}
執行代碼:
public class Main { public static void main(String[] args) { try { Thread1 thread = new Thread1(); thread.start(); Thread.sleep(1000); //A段 thread.suspend(); System.out.println("A = " + System.currentTimeMillis() + " I = " +thread.getI()); //B段 thread.resume(); Thread.sleep(1000); //C段 thread.suspend(); System.out.println("B = " + System.currentTimeMillis() + " I = " + thread.getI()); Thread.sleep(5000); System.out.println("B = " + System.currentTimeMillis() + "I = " + thread.getI()); } catch (InterruptedException e) { e.printStackTrace(); } }}
執行結果:
從執行的時間來看,新開啟的線程確實發生了暫停(當前線程暫停與啟動的時間與另外開啟的線程是一致的),並且能夠成功的恢複運行狀態。
1.8.2suspend與resume方法的缺點——獨佔:
在使用suspend與resume方法時,可能會導致公用的同步對象的獨佔發生,使得其他線程無法訪問公用同步對象。
獨佔代碼:
public class SynchronizedObject { synchronized public void printString() { System.out.println("begin"); if ("a".equals(Thread.currentThread().getName())) { System.out.println("a線程永遠的暫停了,suspend"); Thread.currentThread().suspend(); } System.out.println("end"); }}
執行代碼:
public class Main { public static void main(String[] args) { try { final SynchronizedObject object = new SynchronizedObject(); Thread thread1 = new Thread() { @Override public void run() { object.printString(); } }; thread1.setName("a"); thread1.start(); Thread.sleep(1000); Thread thread2 = new Thread() { @Override public void run() { System.out.println("因為在Thread1中已經暫停了,後面的語句無法執行,所有只列印了begin"); System.out.println("因為此時Thread1已經進入了線程並且鎖定了方法printString()所以什麼都打不出來"); System.out.println("這是死結的一種表現"); object.printString(); } }; thread2.setName("a"); thread2.start(); } catch (InterruptedException e) { e.printStackTrace(); } }}
另一種陷阱式的多線程獨佔問題
線程代碼:
public class Thread2 extends Thread { private long i = 0L; @Override public void run() { while (true) { i++; System.out.println(i); } }}
執行代碼:
public class Main { public static void main(String[] args) { try { Thread2 thread = new Thread2(); thread.start(); Thread.sleep(1000); thread.suspend(); System.out.println("main end"); } catch (InterruptedException e) { e.printStackTrace(); } }}
執行結果:
卡在數字後面,並沒有列印出main end。
原因是在於println()方法,查看其源碼會更加清晰:
由源碼可以得知,在println內部存在同步鎖,當線程在println()內部停止時,同步鎖就永遠不會釋放,就會導致死結。
1.8.3suspend與resume方法的缺點——不同步:
使用這兩個方法容易出現資料不同步的情況。
共用資料類:
public class MyObject { private String username = "1"; private String password = "11"; public void setValue(String u,String p) { this.username = u; if("a".equals(Thread.currentThread().getName())) { System.out.println("停止a線程"); Thread.currentThread().suspend(); } this.password = p; } public void printUsernamePassword() { System.out.println(username + "|||" + password); }}
執行代碼:
public class Main { public static void main(String[] args) { try { final MyObject object = new MyObject(); Thread thread = new Thread() { @Override public void run() { object.setValue("a","aa"); } }; thread.setName("a"); thread.start(); Thread.sleep(1000); Thread thread1 = new Thread() { @Override public void run() { object.printUsernamePassword(); } }; thread1.start(); } catch (InterruptedException e) { e.printStackTrace(); } }}
執行結果:
源碼地址:https://github.com/lilinzhiyu/threadLearning
本文內容是書中內容兼具自己的個人看法所成。可能在個人看法上會有諸多問題(畢竟知識量有限,導致認知也有限),如果讀者覺得有問題請大膽提出,我們可以相互交流、相互學習,歡迎你們的到來,心成意足,等待您的評價。