個人理解,各位大牛請給指導勿噴。
為什麼會出現線程阻塞。
1、當前任務(線程)需要使用另一個任務(線程)的執行結果時,這個時候我們要讓當前任務(線程)阻塞,等待另一個任務(線程)執行完畢,拿到他的處理結果再繼續執行。
2、當多個線程同時訪問臨界區(共享資源)時,而該資源已經有線程占用。由於無法獲得相關的同步鎖,只好進入阻塞狀態,等到獲得了同步鎖,才能恢復運行。
什麼是線程阻塞
所謂的阻塞,就是線程能夠運行,但是某個條件阻止它的運行,當線程處於阻塞狀態時,調度器將忽略線程,不會分配給線程任何CPU時間,直到線程重新進入就緒狀態,它才有可能執行操作。就緒並代表是在運行,所謂的就緒,就是可運行也可不運行,只有獲得調度器分配時間片,線程才可以運行。使線程阻塞的方法:
本文大綱:
一、join()
二、sleep()
三、yield()
四、wait();
join() 方法主要是讓調用該方法的thread完成run方法裡面的任務後, 再執行join()方法後面的代。
主線程生成並起動了子線程,而子線程裡要進行大量的耗時的運算(這裡可以借鑒下線程的作用),當主線程處理完其他的事務後,需要用到子線程的處理結果,這個時候就要用到join();方法了。
//該方法會無限等待,它會一直阻塞當前線程直到目標線程(調用該方法的線程)執行完畢。
public final void join() throws InterruptedException { join(0); }
//該方法需要給出最大等待時間,如果目標線程的執行時間超過給定的時間,那麼當前線程將不在等待目標線程執行結束而直接執行 public final synchronized void join(long millis)throws InterruptedException{}
public class ThreadJoinTest { private static String str=null; public static void main(String[] args) { Thread thread=new Thread(){ @Override public void run() { try { System.out.println("進入"+Thread.currentThread().getName()+"線程"); Thread.sleep(1000); str="hello Word"; System.out.println(Thread.currentThread().getName()+"線程業務處理完畢"); } catch (InterruptedException e) { e.printStackTrace(); } } }; thread.start(); try { //thread.join();//設置main線程等待子線程先處理業務 System.out.println(Thread.currentThread().getName()+"線程處理業務開始"); System.out.println("獲取str值:"+str); } catch (Exception e) { e.printStackTrace(); } } }
執行結果:
main線程處理業務開始
進入Thread-0線程
獲取str值:null
Thread-0線程業務處理完畢
運行代碼,貌似永遠都看不到str的值是"hello Word",而每次都是null,原因很簡單的,因為在thread中的run方法中對str進行賦值操作前休眠了1秒,此時main線程中的System.out.println方法已經執行了,所以很難看到str的值是"hello Word",為了看到str的值是"hello Word",我們的一個思路就是等thread運行結束之後,我們再執行System.out.println就可以了,這時候join方法的作用就顯現出來的,我們把上面的注釋代碼刪除注釋,然後運行,不管運行多少次,輸出的結果都是“hello Word”,從這個例子中我們就可以看到join方法的作用,它能夠調節各個線程之間的運行順序,從而可以實現同步。
如果修改注釋的代碼為thread.join(100);則執行結果為:獲取str值:null ,因為主線程已經等不及了。
join()他讓調用線程在當前線程對象上進行等待當線程執行完畢後,被等待的線程會在推出前調用notifyAll()方法通知所有的等待線程繼續執行。
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }