線程小結二
一、線程休眠
使用靜態方法sleep(long millis)可以讓當前進程暫停一段時間,進入休眠等待狀態,實現人爲的控制線程。
二、線程讓步
通過yield()方法實現
yield()和sleep()的區別:yield()不會阻塞該線程,只是將線程轉換成就緒狀態,讓線程的調度器重新調度一次。
三、線程插隊
通過join()方法來完成
當在某個線程中調用其它線程的join()方法時,調用的線程將被阻塞,直到被join()加入的線程執行完成後纔會繼續執行
多線程同步
一、線程安全性
一個類是線程安全的,是指在被多個線程訪問時,類是可以持續進行正確的行爲。
線程安全問題就是由多個線程同時處理共享資源所導致的
二、同步代碼塊
當多個線程使用同一個共享資源時,可以將處理共享資源的代碼放置到一個代碼塊中,使用sychronized關鍵字來修飾,被稱作同步代碼塊
synchronized(lock){ 操作共享資源代碼塊 }
lock是一個鎖對象,當線程執行同步代碼塊時,首先會檢查鎖對象的標誌位,默認情況下爲1,此時線程會執行同步代碼塊,並將鎖對象的標誌位置0。這時當一個新的線程執行到 這段同步代碼塊時,由於鎖對象的標誌位爲0,新線程會發生阻塞,等待當前線程執行完同步代碼塊後,鎖對象的標誌位被置爲1,新線程才能進入其中並執行。
注意:同步代碼塊中的鎖對象可以是任意類型的對象 ,但多個線程共享的鎖對象必須是唯一的。“任意”說的是共享鎖對象的類型。所以,鎖對象的創建代碼不能放到run()方法中,否則每個線程運行到run()方法都會創建一個新對象,這樣每個線程都會有一個不同的鎖,每個鎖都有自己的標誌位。
三、同步方法
在方法前加入synchronized修飾,被稱爲同步方法。此方法在某一時刻只允許一個線程訪問,訪問該方法的其他線程都會發生阻塞。
同步代碼塊的鎖是自定義的任意類型的對象
同步方法的鎖就是當前調用該方法的對象,就是this指向的對象。如果需要同步的方法是靜態方法,這時會有疑問,靜態方法不需要創建對象就可以直接用“類名.方法名()”方式來調用。如果不創建對象,靜態同步方法的鎖就不會是this,那麼靜態同步方法的鎖是什麼呢?java中靜態方法的鎖是該方法所在類的class對象,該對象可以直接用“類名.class” 的方式獲取
同步代碼塊和同步方法解決多線程問題的優點:解決了多個線程同步時訪問共享數據時的線程安全問題,只要加上同一個鎖,在同一時間內只能有一條線程執行。
缺點:每次都會判斷鎖的狀態,非常消耗資源,效率低下
四、死鎖問題
兩個線程都在等待對方的鎖,便造成了程序的停滯,這種現象稱爲死鎖。
多線程通信
解決這個多線程通信問題,需要控制多個線程按照一定的順序輪流執行。Object類提供了wait()、notify()、notifyAll()方法用於解決線程間通信問題。
wait()使當前線程進入等待狀態,notifu()和notifyAll()用於喚醒當前處於等待狀態的線程。這三個方法的調用者都應該是同步鎖對象,若不是JVM會拋出IllegalMonitorStateException異常