Java知識總結--線程篇

線程

文章部分內容來自於https://blog.csdn.net/zyx1260168395/article/details/105088359線程篇內容

文章部分內容來自於https://blog.csdn.net/qq_41701956/article/details/103253168


目錄

線程

1.1- 創建線程有的常見方式方法

1.2-Runnable和Callable的區別

1.3- start()和run()方法的區別

1.4- sleep() 和 wait()的區別

1.5- notify()和 notifyAll()的區別

1.6-線程池有哪些參數

1.7- 線程池有幾種(5種)?拒絕策略有幾種(4種)?阻塞隊列有幾種(3種)?

1.8- 如何檢測死鎖?

1.9- 防止死鎖

1.10- volatile底層是怎麼實現的?

1.11- volatile與synchronized有什麼區別?

1.12- java中的線程有幾種狀態(5種)

1.13-線程池有幾種狀態(5種)

1.14-在具體多線程編程實踐中,如何選用Runnable還是Thread?

更多多線程常見面試題及答案



1.1- 創建線程有的常見方式方法

  • 通過繼承Thread類實現一個線程

  • 通過實現Runnable接口實現一個線程

  • 實現Callable接口,允許有返回值

  • 使用線程池


1.2-Runnable和Callable的區別

最大的不同點:實現Callable接口的任務線程能返回執行結果;而實現Runnable接口的任務線程不能返回結果;


Callable接口的call()方法允許拋出異常;而Runnable接口的run()方法的異常只能在內部消化,不能繼續上拋;

  • Callable接口支持返回執行結果,此時需要調用FutureTask.get()方法實現,此方法會阻塞主線程直到獲取結果;當不調用此方法時,主線程不會阻塞!


1.3- start()和run()方法的區別

  • start()方法來啓動線程,而啓動後的線程運行的是run()方法中的代碼。

  • run()方法當作普通方法的方式調用時,並不會開啓新的線程。


1.4- sleep() 和 wait()的區別

 

  • sleep():方法是線程類(Thread)的靜態方法,讓調用線程進入睡眠狀態,讓出執行機會給其他線程,等到休眠時間結束後,線程進入就緒狀態和其他線程一起競爭cpu的執行時間。因爲sleep() 是static靜態的方法,他不能改變對象的機鎖,當一個synchronized塊中調用了sleep() 方法,線程雖然進入休眠,但是對象的機鎖沒有被釋放,其他線程依然無法訪問這個對象。

  • wait():wait()是Object類的方法,當一個線程執行到wait方法時,它就進入到一個和該對象相關的等待池,同時釋放對象的機鎖,使得其他線程能夠訪問,可以通過notify,notifyAll方法來喚醒等待的線程。

 


1.5- notify()和 notifyAll()的區別

  • 如果線程調用了對象的 wait()方法,那麼線程便會處於該對象的等待池中,等待池中的線程不會去競爭該對象的鎖。

  • 當有線程調用了對象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機喚醒一個 wait 線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會去競爭該對象鎖。也就是說,調用了notify後只要一個線程會由等待池進入鎖池,而notifyAll會將該對象等待池內的所有線程移動到鎖池中,等待鎖競爭。

  • 優先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖,它還會留在鎖池中,唯有線程再次調用 wait()方法,它纔會重新回到等待池中。而競爭到對象鎖的線程則繼續往下執行,直到執行完了 synchronized 代碼塊,它會釋放掉該對象鎖,這時鎖池中的線程會繼續競爭該對象鎖。


1.6-線程池有哪些參數

最常用的三個參數:

  • corePoolSize:核心線程數
  • queueCapacity:任務隊列容量(阻塞隊列)
  • maxPoolSize:最大線程數

三個參數的作用:

  • 當線程數小於核心線程數時,創建線程。
  • 當線程數大於等於核心線程數,且任務隊列未滿時,將任務放入任務隊列。
  • 當線程數大於等於核心線程數,且任務隊列已滿
    • 若線程數小於最大線程數,創建線程
    • 若線程數等於最大線程數,拋出異常,拒絕任務

1.7- 線程池有幾種(5種)?拒絕策略有幾種(4種)?阻塞隊列有幾種(3種)?

  • 五種線程池:

    ExecutorService threadPool = null;
    threadPool = Executors.newCachedThreadPool();//有緩衝的線程池,線程數 JVM 控制
    threadPool = Executors.newFixedThreadPool(3);//固定大小的線程池
    threadPool = Executors.newScheduledThreadPool(2);//一個能實現定時、週期性任務的線程池
    threadPool = Executors.newSingleThreadExecutor();//單線程的線程池,只有一個線程在工作
    threadPool = new ThreadPoolExecutor();//默認線程池,可控制參數比較多   
    

     

  • 四種拒絕策略:
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//默認,隊列滿了丟任務拋出異常
rejected = new ThreadPoolExecutor.DiscardPolicy();//隊列滿了丟任務不異常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//將最早進入隊列的任務刪,之後再嘗試加入隊列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到線程池失敗,那麼主線程會自己去執行該任務
  •  三種阻塞隊列:

    BlockingQueue<Runnable> workQueue = null;
    workQueue = new ArrayBlockingQueue<>(5);//基於數組的先進先出隊列,有界
    workQueue = new LinkedBlockingQueue<>();//基於鏈表的先進先出隊列,無界
    workQueue = new SynchronousQueue<>();//無緩衝的等待隊列,無界
    

     


1.8- 如何檢測死鎖?

利用Java自帶工具JConsole
Java線程死鎖查看分析方法


1.9- 防止死鎖

死鎖的四個必要條件:

  • 互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至佔有該資源的進程使用完成後釋放該資源
  • 請求和保持條件:進程獲得一定的資源之後,又對其他資源發出請求,但是該資源可能被其他進程佔有,此事請求阻塞,但又對自己獲得的資源保持不放
  • 不可剝奪條件:是指進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完後自己釋放
  • 環路等待條件:是指進程發生死鎖後,若干進程之間形成一種頭尾相接的循環等待資源關係

這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之 一不滿足,就不會發生死鎖。

理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和 解除死鎖。

所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確 定資源的合理分配算法,避免進程永久佔據系統資源。

此外,也要防止進程在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。


1.10- volatile底層是怎麼實現的?

當一個變量定義爲volatile後,它將具備兩種特性:1. 可見性,2. 禁止指令重排序。

可見性:編譯器爲了加快程序運行速度,對一些變量的寫操作會現在寄存器或CPU緩存上進行,最後寫入內存。而在這個過程中,變量的新值對其它線程是不可見的。當對volatile標記的變量進行修改時,先當前處理器緩存行的數據寫回到系統內存,然後這個寫回內存的操作會使其他CPU裏緩存了該內存地址的數據無效。

處理器使用嗅探技術保證它的內部緩存、系統內存和其他處理器的緩存的數據在總線上保持一致。如果一個正在共享的狀態的地址被嗅探到其他處理器打算寫內存地址,那麼正在嗅探的處理器將使它的緩存行無效,在下次訪問相同內存地址時,強制執行緩存行填充。 


1.11- volatile與synchronized有什麼區別?

  • volatile僅能使用在變量上,synchronized則可以使用在方法、類、同步代碼塊等等。

  • volatile只能保證可見性和有序性,不能保證原子性。而synchronized都可以保證。

  • volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞.


1.12- java中的線程有幾種狀態(5種)

  • NEW:新建狀態,創建了一個線程對象

  • RUNNABLE:可以運行狀態,線程調用了start()方法。

  • BLOCKED:阻塞狀態,遇到了阻塞事件,或者等待鎖對象.

  • WAITING:等待狀態。wait(),join()/TIMED_WAITING:等待狀態,sleep()

  • TERMINATED:終止狀態


1.13-線程池有幾種狀態5種

Running、ShutDown、Stop、Tidying、Terminated。


1.14-在具體多線程編程實踐中,如何選用Runnable還是Thread?

 

 Java中實現多線程有兩種方法:繼承Thread類、實現Runnable接口,在程序開發中只要是多線程,肯定永遠以實現Runnable接口爲主,因爲實現Runnable接口相比繼承Thread類有如下優勢:

    1、可以避免由於Java的單繼承特性而帶來的侷限;

    2、增強程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的;

 


更多多線程常見面試題及答案

 

//持續更新。。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章