標籤:android c style class blog code
有一道這種面試題:開啟一個子線程和主線程同一時候運行,子線程輸出10次後接著主線程輸出100次,如此重複50次。先看以下代碼:
package com.maso.test;/** * * @author Administrator * 兩個線程,當中是一個主線程,第一個線程先運行輸出10次,主線程接著運行輸出100次,如此重複50次 */public class ThreadTest3 implements Runnable{private static Test test;@Overridepublic void run() {for(int i=0; i<50; i++){test.f1(i);}}public static void main(String[] args) {test = new Test();new Thread(new ThreadTest3()).start();for(int i=0; i<50; i++){test.f2(i);}}/** * 將控制和邏輯及資料分類(該類就是資料) * @author Administrator * */static class Test{private boolean isf1 = true;/** * 輸出10次 */public synchronized void f1(int j){if(!isf1){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int i=1; i<=10; i++){System.out.println(Thread.currentThread().getName() + "第" + j + "次輪巡,輸出" + i);}isf1 = false;notify();}/** * 輸出100次 */public synchronized void f2(int j){if(isf1){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int i=1; i<=100; i++){System.out.println(Thread.currentThread().getName() + "第" + j + "次輪巡,輸出" + i);}isf1 = true;notify();}}}
上面推斷用的是if語句,這樣做看似沒有什麼問題,實際上這樣做是不安全的,由於線程在等待的過程中有可能被假喚醒,所以我們須要使用while語句。另外在使用wait和notify的時候須要注意一下幾點:
1、調用object的wait方法和notity方法時,必須先獲得object的對象鎖(必須寫在synchronized中)。
2、假設調用了object的wait方法,則該線程就放掉了對象鎖。
3、假設A1、A2、A3都在object.wait(),則B調用object.notify()僅僅能喚醒A1、A2、A3中的一個(詳細哪一個由JVM決定)
4、object.notifyAll()能夠喚醒所有。
5、B在喚醒A的時候,B假設還持有對象鎖,則要等到B釋放鎖後,A才有機會運行。
Sleep和Wait有什麼差別?
sleep()並不釋放對象鎖,wait()釋放對象鎖。可是wait()和sleep()都能夠通過interrupt()方法打斷線程的暫停狀態,從而使線程立馬拋出InterruptedException。假設線程A希望馬上結束線程B,則能夠對線程B相應的Thread執行個體調用interrupt方法。假設此刻線程B正在wait/sleep/join,則線程B會立馬拋出InterruptedException,在catch() {} 中直接return就可以安全地結束線程。須要注意的是,InterruptedException是線程自己從內部拋出的,並非interrupt()方法拋出的。對某一線程調用interrupt()時,假設該線程正在運行普通的代碼,那麼該線程根本就不會拋出InterruptedException。可是,一旦該線程進入到wait()/sleep()/join()後,就會立馬拋出InterruptedException。
以下我們來看看線程的生命週期:
實現線程調度的方法例如以下:
1、sleep():該線程是讓線程休眠一定的時間,須要捕獲InterruptedException
2、yield():暫停當前線程,讓同等級優先權的線程運行,假設沒有同等級優先權線程則不會起作用。起作用後會讓出CPU已耗用時間,進入就緒狀態。
3、join():讓一個線程等待調用join方法的線程運行完成後再繼續運行。
看一段代碼:
public class ThreadTest4 implements Runnable{private static int a = 0;@Overridepublic void run() {for(int i=0; i<10; i++){a++;}}public static void main(String[] args) {new Thread(new ThreadTest4()).start();System.out.println(a);}}
這段代碼會輸出10嗎?答案是不會的,由於在啟動子線程後,就立馬輸出了a的值,此時子線程對a還沒有操作。改動例如以下:
public class ThreadTest4 implements Runnable{private static int a = 0;@Overridepublic void run() {for(int i=0; i<10; i++){a++;}}public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new ThreadTest4());t.start();t.join();System.out.println(a);}}
這回輸出了10,join()方法的作用由此可見,它會讓其它線程等待該線程運行完成後再運行。