1、Thread類的常用靜態方法:
①、static Thread currentThread(); 返回對當前正在執行的線程對象的引用。
②、static void sleep(long millis) throws InterruptedException 讓當前正在執行的線程休眠(暫停執行),
休眠時間millis(毫秒)指定。
③、static void sleep(long millis,int nanos) throws InterruptedException 讓當前正在執行的線程休眠,
休眠時間由millis(毫秒)和nanos(納秒)指定。
④、static void yield(); 暫停當前正在執行的線程,轉而執行其他線程.
⑤、static boolean interrupted();
2、Thread類的常用構造方法:
①、Thread() 創建一個新線程
②、Thread(String name) 創建一個指定名稱的線程
③、Thread(Runnable target) 利用 Runnable 對象創建一個線程,啓動時將執行該對象的 run 方法
④、Thread(Runnable target, String name) 利用 Runnable 對象創建一個線程,並指定該線程的名稱
3、Thread類的其它常用方法:
①、void start() 啓動線程
②、final void setName(String name) 設置線程的名稱
③、final String getName() 返回線程的名稱
④、final void setPriority(int newPriority) 設置線程的優先級
⑤、final int getPriority() 返回線程的優先級
4、與線程相關的一些方法:
①、final void join()throws InterruptedException 等待線程終止
②、final boolean isAlive() 判斷線程是否處於活動狀態
③、void interrupted() 中斷線程
④、sleep、yield和join:sleep和yield都是Thread類的靜態方法,都會使當前處於運行狀態的線程放棄CPU,但兩者的區別在於:
sleep給其它線程運行的機會,但不考慮其它線程的優先級;但yield只會讓位給相同或更高優先級的線程;
當線程執行了sleep方法後,將轉到阻塞狀態,而執行了yield方法之後,則轉到就緒狀態;
sleep方法有可能拋出異常,而yield則沒有;在一般情況下,我們更建議使用sleep方法。
join方法用於等待其它線程結束,當前運行的線程可以調用另一線程的join方法,當前運行線程將轉到阻塞狀態, 直至另一線程執行結束,它纔會恢復運行。
1)、sleep用法:
Thread.sleep(long millis)和 Thread.sleep(long millis, int nanos) 靜態方法強制當前正在執行的線程休眠
(暫停執行),以“減慢線程”。當線程睡眠時,它入睡在某個地方,在甦醒之前不會返回到可運行狀態。當睡 眠時間到期,則返回到可運行狀態。
①、線程睡眠的原因:線程執行太快,或者需要強制進入下一輪
②、睡眠的實現:調用靜態方法。
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
③、睡眠的位置:爲了讓其他線程有機會執行,可以將Thread.sleep()的調用放線程run()之內。這樣才能保證該 線程執行過程中會睡眠。
④、線程睡眠是幫助所有線程獲得運行機會的最好方法。
⑤、線程睡眠到期自動甦醒,並返回到可運行狀態,不是運行狀態。sleep()中指定的時間是線程不會運行的最短 時間。因此,sleep()方法不能保證該線程睡眠到期後就開始執行。sleep()是靜態方法,只能控制當前正在運 行的線程。
①、Thread.yield() 方法的作用是:暫停當前正在執行的線程對象,並執行其他線程,讓相同優先級的線程之間能適 當的輪轉執行。
②、yield() 做的是讓當前運行線程回到可運行狀態,以允許具有相同優先級的其他線程獲得運行機會。但是,實際 中無法保證 yield() 達到讓步目的,因爲讓步的線程還有可能被線程調度程序再次選中。
③、結論:yield() 從未導致線程轉到等待/睡眠/阻塞狀態。在大多數情況下,yield() 將導致線程從運行狀態轉到可 運行狀態,但有可能沒有效果。
Thread 的非靜態方法 join() 讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前,B不能工作。
常用於主線程需要用到子線程執行完後的結果,即主線程需要等待子線程執行完成後再結束。
例:創建並啓動線程t,加入到當前運行的線程中
MyThread t = new MyThread();t.start();
t.join();
5、與後臺線程相關的方法:
①、final void setDaemon(boolean on) 將該線程設置爲後臺線程
②、final boolean isDaemon() 判斷該線程是否爲後臺線程
注意:要將某個線程設置爲後臺線程的話,必須在它啓動之前調用 setDeamon 方法;
默認情況下,由前臺線程創建的線程仍是前臺線程,由後臺線程創建的線程仍是後臺線程。
當多個線程共享數據時,往往可能發生數據讀寫不一致的情況,這時候就需要使用同步
1、線程同步的概念
①、線程是一份獨立運行的程序,有自己專用的運行棧。線程有可能和其他線程共享一些資源,比如,內存, 文件,數據庫等
②、多個線程同時讀寫同一份共享資源時,可能會引起衝突。所以引入線程“同步”機制,即各線程間要有先來後 到;
③、同步就是排隊:幾個線程之間要排隊,一個一個對共享資源進行操作,而不是同時進行操作;
2、實現線程同步的方式
確保一個時間點只有一個線程訪問共享資源。可以給共享資源加一把鎖,這把鎖只有一把鑰匙。哪個線程獲取了這 把鑰匙,纔有權利訪問該共享資源。
在Java代碼中實現同步要完成以下兩步:
①、把競爭訪問的資源標識爲 private
②、使用 synchronized(同步的) 關鍵字同步方法或代碼塊。
3、synchronized關鍵字的使用:
1)、同步的方法:
①、使用 synchronized 修飾的方法:
訪問修飾符 synchronized 數據返回類型 方法名(){
......
}
②、它鎖定的是調用這個同步方法的對象。其它線程不能同時訪問這個對象中任何一個 synchronized 方法。
③、不同的對象實例的 synchronized 方法是不相干擾的。其它線程照樣可以同時訪問相同類的另一個對象實例中 的 synchronized 方法。
使用同步方法,可以方便的將類變成線程安全的類。
防止多個線程同時訪問這個類中的 synchronized static 方法。它可以對類的所有對象實例起作用。
訪問修飾符 synchronized static 數據返回類型 方法名(){
......
}
2)、同步語句塊
只對這個區塊的資源實行互斥訪問:
synchronized(共享對象名){
被同步的代碼段
}
它鎖定的是共享對象名對應的當前對象。
線程中實現同步塊一般是在 run 方法中添加。
如果沒有明確的對象作爲鎖,只想讓一塊代碼同步時,可以創建一個特殊的實例變量:
/*特殊的實例變量
(零長度的byte數組對象創建起來將比任何對象都經濟)*/
private byte[] lock = new byte[0];
synchronized(lock){
被同步的代碼段
}
4、線程同步的注意事項
①、不要對線程安全類的所有方法都進行同步,只對那些會改變共享資源方法的進行同步。同步塊越大,多線 程的效率越低
②、synchronized 關鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器、抽象方法、成員屬性等。
③、synchronized 關鍵字是不能繼承的。
④、無論 synchronized 關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作 鎖。
⑤、搞清楚 synchronized 鎖定的是哪個對象。