<code id="nbzwf"></code>
  1. <var id="nbzwf"></var>
    1. <meter id="nbzwf"></meter>
        <option id="nbzwf"><menuitem id="nbzwf"></menuitem></option><listing id="nbzwf"><delect id="nbzwf"><p id="nbzwf"></p></delect></listing>
        • 穩了!Java并發編程71道面試題及答案(下)

          發布:51Code 時間: 2019-03-08 14:11

        • 查看: 穩了!Java并發編程71道面試題及答案(上) 36、什么叫線程安全?servlet是線程安全嗎? 線程安全是編程中的術語,指某個函數、函數庫在多線程環境中被調用時,能夠正確地處理...

        • 點擊查看:穩了!Java并發編程71道面試題及答案(上)

                 36、什么叫線程安全?servlet是線程安全嗎?

          線程安全是編程中的術語,指某個函數、函數庫在多線程環境中被調用時,能夠正確地處理多個線程之間的共享變量,使程序功能正確完成。

          Servlet不是線程安全的,servlet是單實例多線程的,當多個線程同時訪問同一個方法,是不能保證共享變量的線程安全性的。

          Struts2的action是多實例多線程的,是線程安全的,每個請求過來都會new一個新的action分配給這個請求,請求完成后銷毀。

          SpringMVC的Controller是線程安全的嗎?不是的,和Servlet類似的處理流程

          Struts2好處是不用考慮線程安全問題;Servlet和SpringMVC需要考慮線程安全問題,但是性能可以提升不用處理太多的gc,可以使用ThreadLocal來處理多線程的問題。

          37、volatile有什么用?能否用一句話說明下volatile的應用場景?

          volatile保證內存可見性和禁止指令重排。

          volatile用于多線程環境下的單次操作(單次讀或者單次寫)。

          38、為什么代碼會重排序?

          在執行程序時,為了提供性能,處理器和編譯器常常會對指令進行重排序,但是不能隨意重排序,不是你想怎么排序就怎么排序,它需要滿足以下兩個條件:

          在單線程環境下不能改變程序運行的結果;

          存在數據依賴關系的不允許重排序

          需要注意的是:重排序不會影響單線程環境的執行結果,但是會破壞多線程的執行語義。

          39、在java中wait和sleep方法的不同?

          最大的不同是在等待時wait會釋放鎖,而sleep一直持有鎖。Wait通常被用于線程間交互,sleep通常被用于暫停執行。

          直接了解的深入一點吧:

          在Java中線程的狀態一共被分成6種:

          初始態:

          創建一個Thread對象,但還未調用start()啟動線程時,線程處于初始態。

          運行態:

          在Java中,運行態包括就緒態和運行態。

          就緒態該狀態下的線程已經獲得執行所需的所有資源,只要CPU分配執行權就能運行。所有就緒態的線程存放在就緒隊列中。

          運行態獲得CPU執行權,正在執行的線程。由于一個CPU同一時刻只能執行一條線程,因此每個CPU每個時刻只有一條運行態的線程。

          阻塞態:

          當一條正在執行的線程請求某一資源失敗時,就會進入阻塞態。而在Java中,阻塞態專指請求鎖失敗時進入的狀態。由一個阻塞隊列存放所有阻塞態的線程。處于阻塞態的線程會不斷請求資源,一旦請求成功,就會進入就緒隊列,等待執行。PS:鎖、IO、Socket等都資源。

          等待態:

          當前線程中調用wait、join、park函數時,當前線程就會進入等待態。也有一個等待隊列存放所有等待態的線程。線程處于等待態表示它需要等待其他線程的指示才能繼續運行。進入等待態的線程會釋放CPU執行權,并釋放資源(如:鎖)

          超時等待態:

          當運行中的線程調用sleep(time)、wait、join、parkNanos、parkUntil時,就會進入該狀態;它和等待態一樣,并不是因為請求不到資源,而是主動進入,并且進入后需要其他線程喚醒;進入該狀態后釋放CPU執行權 和 占有的資源。與等待態的區別:到了超時時間后自動進入阻塞隊列,開始競爭鎖。

          終止態:

          線程執行結束后的狀態。

          注意:

          wait()方法會釋放CPU執行權和占有的鎖。

          sleep(long)方法僅釋放CPU使用權,鎖仍然占用;線程被放入超時等待隊列,與yield相比,它會使線程較長時間得不到運行。

          yield()方法僅釋放CPU執行權,鎖仍然占用,線程會被放入就緒隊列,會在短時間內再次執行。

          wait和notify必須配套使用,即必須使用同一把鎖調用;

          wait和notify必須放在一個同步塊中調用wait和notify的對象必須是他們所處同步塊的鎖對象。

          40、一個線程運行時發生異常會怎樣?

          如果異常沒有被捕獲該線程將會停止執行。Thread.UncaughtExceptionHandler是用于處理未捕獲異常造成線程突然中斷情況的一個內嵌接口。當一個未捕獲異常將造成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler并將線程和異常作為參數傳遞給handler的uncaughtException()方法進行處理。

          41、如何在兩個線程間共享數據?

          在兩個線程間共享變量即可實現共享。

          一般來說,共享變量要求變量本身是線程安全的,然后在線程內使用的時候,如果有對共享變量的復合操作,那么也得保證復合操作的線程安全性。

          42、Java中notify 和 notifyAll有什么區別?

          notify() 方法不能喚醒某個具體的線程,所以只有一個線程在等待的時候它才有用武之地。而notifyAll()喚醒所有線程并允許他們爭奪鎖確保了至少有一個線程能繼續運行。

          43、為什么wait, notify 和 notifyAll這些方法不在thread類里面?

          一個很明顯的原因是JAVA提供的鎖是對象級的而不是線程級的,每個對象都有鎖,通過線程獲得。由于wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬于對象。

          44、什么是ThreadLocal變量?

          ThreadLocal是Java里一種特殊的變量。每個線程都有一個ThreadLocal就是每個線程都擁有了自己獨立的一個變量,競爭條件被徹底消除了。它是為創建代價高昂的對象獲取線程安全的好方法,比如你可以用ThreadLocal讓SimpleDateFormat變成線程安全的,因為那個類創建代價高昂且每次調用都需要創建不同的實例所以不值得在局部范圍使用它,如果為每個線程提供一個自己獨有的變量拷貝,將大大提高效率。首先,通過復用減少了代價高昂的對象的創建個數。其次,你在沒有使用高代價的同步或者不變性的情況下獲得了線程安全。

          45、Java中interrupted 和 isInterrupted方法的區別?

          interrupt方法用于中斷線程。調用該方法的線程的狀態為將被置為”中斷”狀態。 注意:線程中斷僅僅是置線程的中斷狀態位,不會停止線程。需要用戶自己去監視線程的狀態為并做處理。支持線程中斷的方法(也就是線程中斷后會拋出interruptedException的方法)就是在監視線程的中斷狀態,一旦線程的中斷狀態被置為“中斷狀態”,就會拋出中斷異常。

          interrupted查詢當前線程的中斷狀態,并且清除原狀態。如果一個線程被中斷了,第一次調用interrupted則返回true,第二次和后面的就返回false了。

          isInterrupted僅僅是查詢當前線程的中斷狀態

          46、為什么wait和notify方法要在同步塊中調用?

          Java API強制要求這樣做,如果你不這么做,會拋出IllegalMonitorStateException異常。還有一個原因是為了避免wait和notify之間產生競態條件。

          47、為什么你應該在循環中檢查等待條件?

          處于等待狀態的線程可能會收到錯誤警報和偽喚醒,如果不在循環中檢查等待條件,程序就會在沒有滿足結束條件的情況下退出。

          48、Java中的同步集合與并發集合有什么區別?

          同步集合與并發集合都為多線程和并發提供了合適的線程安全的集合,不過并發集合的可擴展性更高。在Java1.5之前程序員們只有同步集合來用且在多線程并發的時候會導致爭用,阻礙了系統的擴展性。

          Java5介紹了并發集合像ConcurrentHashMap,不僅提供線程安全還用鎖分離和內部分區等現代技術提高了可擴展性。

          49、什么是線程池? 為什么要使用它?

          創建線程要花費昂貴的資源和時間,如果任務來了才創建線程那么響應時間會變長,而且一個進程能創建的線程數有限。為了避免這些問題,在程序啟動的時候就創建若干線程來響應處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的線程池。

          50、怎么檢測一個線程是否擁有鎖?

          在java.lang.Thread中有一個方法叫holdsLock(),它返回true如果當且僅當當前線程擁有某個具體對象的鎖。

          51、JVM中哪個參數是用來控制線程的棧堆棧小的?

          -Xss 每個線程的棧大小

          52、Thread類中的yield方法有什么作用?

          使當前線程從執行狀態(運行狀態)變為可執行態(就緒狀態)。

          當前線程到了就緒狀態,那么接下來哪個線程會從就緒狀態變成執行狀態呢?可能是當前線程,也可能是其他線程,看系統的分配了。

          53、Java中ConcurrentHashMap的并發度是什么?

          ConcurrentHashMap把實際map劃分成若干部分來實現它的可擴展性和線程安全。這種劃分是使用并發度獲得的,它是ConcurrentHashMap類構造函數的一個可選參數,默認值為16,這樣在多線程情況下就能避免爭用。

          在JDK8后,它摒棄了Segment(鎖段)的概念,而是啟用了一種全新的方式實現,利用CAS算法。同時加入了更多的輔助變量來提高并發度,具體內容還是查看源碼吧。

          54、Java中Semaphore是什么?

          Java中的Semaphore是一種新的同步類,它是一個計數信號。從概念上講,從概念上講,信號量維護了一個許可集合。如有必要,在許可可用前會阻塞每一個 acquire(),然后再獲取該許可。每個 release()添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore只對可用許可的號碼進行計數,并采取相應的行動。信號量常常用于多線程的代碼中,比如數據庫連接池。

          55、Java線程池中submit() 和 execute()方法有什么區別?

          兩個方法都可以向線程池提交任務,execute()方法的返回類型是void,它定義在Executor接口中。

          而submit()方法可以返回持有計算結果的Future對象,它定義在ExecutorService接口中,它擴展了Executor接口,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。

          56、什么是阻塞式方法?

          阻塞式方法是指程序會一直等待該方法完成期間不做其他事情,ServerSocket的accept()方法就是一直等待客戶端連接。這里的阻塞是指調用結果返回之前,當前線程會被掛起,直到得到結果之后才會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。

          57、Java中的ReadWriteLock是什么?

          讀寫鎖是用來提升并發程序性能的鎖分離技術的成果。

          58、volatile 變量和 atomic 變量有什么不同?

          Volatile變量可以確保先行關系,即寫操作會發生在后續的讀操作之前, 但它并不能保證原子性。例如用volatile修飾count變量那么 count++ 操作就不是原子性的。

          而AtomicInteger類提供的atomic方法可以讓這種操作具有原子性如getAndIncrement()方法會原子性的進行增量操作把當前值加一,其它數據類型和引用變量也可以進行相似操作。

          59、可以直接調用Thread類的run ()方法么?

          當然可以。但是如果我們調用了Thread的run()方法,它的行為就會和普通的方法一樣,會在當前線程中執行。為了在新的線程中執行我們的代碼,必須使用Thread.start()方法。

          60、如何讓正在運行的線程暫停一段時間?

          我們可以使用Thread類的Sleep()方法讓線程暫停一段時間。需要注意的是,這并不會讓線程終止,一旦從休眠中喚醒線程,線程的狀態將會被改變為Runnable,并且根據線程調度,它將得到執行。

          61、你對線程優先級的理解是什么?

          每一個線程都是有優先級的,一般來說,高優先級的線程在運行時會具有優先權,但這依賴于線程調度的實現,這個實現是和操作系統相關的(OS dependent)。我們可以定義線程的優先級,但是這并不能保證高優先級的線程會在低優先級的線程前執行。線程優先級是一個int變量(從1-10),1代表最低優先級,10代表最高優先級。

          java的線程優先級調度會委托給操作系統去處理,所以與具體的操作系統優先級有關,如非特別需要,一般無需設置線程優先級。

          62、什么是線程調度器和時間分片?

          線程調度器是一個操作系統服務,它負責為Runnable狀態的線程分配CPU時間。一旦我們創建一個線程并啟動它,它的執行便依賴于線程調度器的實現。 同上一個問題,線程調度并不受到Java虛擬機控制,所以由應用程序來控制它是更好的選擇(也就是說不要讓你的程序依賴于線程的優先級)。

          時間分片是指將可用的CPU時間分配給可用的Runnable線程的過程。分配CPU時間可以基于線程優先級或者線程等待的時間。

          63、你如何確保main()方法所在的線程是Java 程序最后結束的線程?

          我們可以使用Thread類的join()方法來確保所有程序創建的線程在main()方法退出前結束。

          64、線程之間是如何通信的?

          當線程間是可以共享資源時,線程間通信是協調它們的重要的手段。Object類中wait()、notify()、notifyAll()方法可以用于線程間通信關于資源的鎖的狀態。

          65、為什么線程通信的方法wait()、notify()和notifyAll()被定義在Object 類里?

          Java的每個對象中都有一個鎖(monitor,也可以成為監視器) 并且wait(),notify()等方法用于等待對象的鎖或者通知其他線程對象的監視器可用。在Java的線程中并沒有可供任何對象使用的鎖和同步器。這就是為什么這些方法是Object類的一部分,這樣Java的每一個類都有用于線程間通信的基本方法。

          66、為什么wait()、notify()和notifyAll ()必須在同步方法或者同步塊中被調用?

          當一個線程需要調用對象的wait()方法的時候,這個線程必須擁有該對象的鎖,接著它就會釋放這個對象鎖并進入等待狀態直到其他線程調用這個對象上的notify()方法。同樣的,當一個線程需要調用對象的notify()方法時,它會釋放這個對象的鎖,以便其他在等待的線程就可以得到這個對象鎖。由于所有的這些方法都需要線程持有對象的鎖,這樣就只能通過同步來實現,所以他們只能在同步方法或者同步塊中被調用。

          67、為什么Thread類的sleep()和yield ()方法是靜態的?

          Thread類的sleep()和yield()方法將在當前正在執行的線程上運行。所以在其他處于等待狀態的線程上調用這些方法是沒有意義的。這就是為什么這些方法是靜態的。它們可以在當前正在執行的線程中工作,并避免程序員錯誤的認為可以在其他非運行線程調用這些方法。

          68、如何確保線程安全?

          在Java中可以有很多方法來保證線程安全——同步,使用原子類實現并發鎖,使用volatile關鍵字,使用不變類和線程安全類。

          69、同步方法和同步塊,哪個是更好的選擇?

          同步塊是更好的選擇,因為它不會鎖住整個對象(當然可以讓它鎖住整個對象)。同步方法會鎖住整個對象,哪怕這個類中有多個不相關聯的同步塊,這通常會導致他們停止執行并需要等待獲得這個對象上的鎖。

          同步塊更要符合開放調用的原則,只在需要鎖住的代碼塊鎖住相應的對象,這樣從側面來說也可以避免死鎖。

          70、如何創建守護線程?

          使用Thread類的setDaemon(true)方法可以將線程設置為守護線程,需要注意的是,需要在調用start()方法前調用這個方法,否則會拋出IllegalThreadStateException異常。

          71、什么是Java Timer 類?如何創建一個有特定時間間隔的任務?

          java.util.Timer是一個工具類,可以用于安排一個線程在未來的某個特定時間執行。Timer類可以用安排一次性任務或者周期任務。

          java.util.TimerTask是一個實現了Runnable接口的抽象類,我們需要去繼承這個類來創建我們自己的定時任務并使用Timer去安排它的執行。

          目前有開源的Qurtz可以用來創建定時任務。

          文章作者:烏梟 版權歸原作者所有
          如涉及知識產權問題,請權利人聯系博為峰小編(021-64471599-8103),我們將立即處理。
        • 上一篇:穩了!Java并發編程71道面試題及答案(上)

          下一篇:如何開始使用 Java 機器學習

        網站導航
        Copyright(C)51Code軟件開發網 2003-2019 , 滬ICP備05003035號-6
        北京快三路线温都水城

          <code id="nbzwf"></code>
        1. <var id="nbzwf"></var>
          1. <meter id="nbzwf"></meter>
              <option id="nbzwf"><menuitem id="nbzwf"></menuitem></option><listing id="nbzwf"><delect id="nbzwf"><p id="nbzwf"></p></delect></listing>

                <code id="nbzwf"></code>
              1. <var id="nbzwf"></var>
                1. <meter id="nbzwf"></meter>
                    <option id="nbzwf"><menuitem id="nbzwf"></menuitem></option><listing id="nbzwf"><delect id="nbzwf"><p id="nbzwf"></p></delect></listing>
                    500时时彩套利方法大全 乌鲁木齐站街女一条街 黑客为什么不攻击赌博 拉萨按摩体验 中国足彩网手机版 时时彩套利新技术 澳洲幸运5破解软件 时时彩单双怎么跟 e尊国际28 北京pk10赛车全天在线版