多線程常見面試題及答案

一、如何在Java中實現線程(4種)?html

 

1.繼承Thread類,重寫run方法(其實Thread類自己也實現了Runnable接口)java

2.實現Runnable接口,重寫run方法程序員

3.實現Callable接口,重寫call方法(有返回值)算法

4.使用線程池(有返回值)數據庫

https://www.cnblogs.com/duanjiapingjy/p/9434244.htmlhttps://www.cnblogs.com/duanjiapingjy/p/9434244.html編程

 

二、在具體多線程編程實踐中,如何選用Runnable仍是Thread?小程序

  Java中實現多線程有兩種方法:繼承Thread類、實現Runnable接口,在程序開發中只要是多線程,確定永遠以實現Runnable接口爲主,由於實現Runnable接口相比繼承Thread類有以下優點:設計模式

 

    一、能夠避免因爲Java的單繼承特性而帶來的侷限;api

 

    二、加強程序的健壯性,代碼可以被多個線程共享,代碼與數據是獨立的;數組

 

適合多個相同程序代碼的線程區處理同一資源的狀況。

 

三、Thread類中的start()和run()方法有什麼區別?

 start()方法來啓動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼: 經過調用Thread類的start()方法來啓動一個線程,這時此線程是處於就緒狀態,並無運行。而後經過此Thread類調用方法run()來完成其運行操做的,這裏方法run()稱爲線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程終止,而CPU再運行其它線程。

  run()方法看成普通方法的方式調用,程序仍是要順序執行,仍是要等待run方法體執行完畢後纔可繼續執行下面的代碼: 而若是直接用run方法,這只是調用一個方法而已,程序中依然只有主線程–這一個線程,其程序執行路徑仍是隻有一條,這樣就沒有達到多線程的目的。

 

四、Java中Runnable和Callable有什麼不一樣

相同點:

1. 二者都是接口;(廢話)

2. 二者均可用來編寫多線程程序;

3. 二者都須要調用Thread.start()啓動線程;

 

不一樣點:

1. 二者最大的不一樣點是:實現Callable接口的任務線程能返回執行結果;而實現Runnable接口的任務線程不能返回結果;

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

 

注意點:

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

五、如何避免死鎖?

1. 加鎖順序

按照順序加鎖是一種有效的死鎖預防機制。可是,這種方式須要你事先知道全部可能會用到的鎖(並對這些鎖作適當的排序),但總有些時候是沒法預知的。

 

2. 加鎖時限

另一個能夠避免死鎖的方法是在嘗試獲取鎖的時候加一個超時時間,這也就意味着在嘗試獲取鎖的過程當中若超過了這個時限該線程則放棄對該鎖請求。

3.死鎖檢測

死鎖檢測是一個更好的死鎖預防機制,它主要是針對那些不可能實現按序加鎖而且鎖超時也不可行的場景。

每當一個線程得到了鎖,會在線程和鎖相關的數據結構中(map、graph等等)將其記下。除此以外,每當有線程請求鎖,也須要記錄在這個數據結構中。

當一個線程請求鎖失敗時,這個線程能夠遍歷鎖的關係圖看看是否有死鎖發生。例如,線程A請求鎖7,可是鎖7這個時候被線程B持有,這時線程A就能夠檢查一下線程B是否已經請求了線程A當前所持有的鎖。若是線程B確實有這樣的請求,那麼就是發生了死鎖(線程A擁有鎖1,請求鎖7;線程B擁有鎖7,請求鎖1)。

固然,死鎖通常要比兩個線程互相持有對方的鎖這種狀況要複雜的多。線程A等待線程B,線程B等待線程C,線程C等待線程D,線程D又在等待線程A。線程A爲了檢測死鎖,它須要遞進地檢測全部被B請求的鎖。從線程B所請求的鎖開始,線程A找到了線程C,而後又找到了線程D,發現線程D請求的鎖被線程A本身持有着。這是它就知道發生了死鎖。

 

六、Java多線程中調用wait() 和 sleep()方法有什麼不一樣?

 

共同點: 

1. 他們都是在多線程的環境下,均可以在程序的調用處阻塞指定的毫秒數,並返回。 

 

2. wait()和sleep()均可以經過interrupt()方法 打斷線程的暫停狀態 ,從而使線程馬上拋出InterruptedException。 

   若是線程A但願當即結束線程B,則能夠對線程B對應的Thread實例調用interrupt方法。若是此刻線程B正在wait/sleep /join,則線程B會馬上拋出InterruptedException,在catch() {} 中直接return便可安全地結束線程。 

   須要注意的是,InterruptedException是線程本身從內部拋出的,並非interrupt()方法拋出的。對某一線程調用 interrupt()時,若是該線程正在執行普通的代碼,那麼該線程根本就不會拋出InterruptedException。可是,一旦該線程進入到 wait()/sleep()/join()後,就會馬上拋出InterruptedException 。 

 

不一樣點: 

1. Thread類的方法:sleep(),yield()等 

   Object的方法:wait()和notify()等 

   

2. 每一個對象都有一個鎖來控制同步訪問。Synchronized關鍵字能夠和對象的鎖交互,來實現線程的同步。 

   sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其餘線程能夠使用同步控制塊或者方法。 

 

3. wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用 

4. sleep必須捕獲異常,而wait,notify和notifyAll不須要捕獲異常   

 

七、什麼是Executor框架

咱們知道線程池就是線程的集合,線程池集中管理線程,以實現線程的重用,下降資源消耗,提升響應速度等。線程用於執行異步任務,單個的線程既是工做單元也是執行機制,從JDK1.5開始,爲了把工做單元與執行機制分離開,Executor框架誕生了,他是一個用於統一建立與運行的接口。Executor框架實現的就是線程池的功能。

八、在Java中Executor和Executors的區別

Executor是http://lib.csdn.net/base/javaee" \o "Java EE知識庫" \t "https://blog.csdn.net/qq991029781/article/details/_blankJava線程池的頂級接口;

Executors是一個類, Executors類提供了若干個靜態方法,用於生成不一樣類型的線程池:

九、什麼是多線程中的上下文切換?

即便是單核CPU也支持多線程執行代碼,CPU經過給每一個線程分配CPU時間片來實現這個機制。時間片是CPU分配給各個線程的時間,由於時間片很是短,因此CPU經過不停地切換線程執行,讓咱們感受多個線程時同時執行的,時間片通常是幾十毫秒(ms)。

CPU經過時間片分配算法來循環執行任務,當前任務執行一個時間片後會切換到下一個任務。可是,在切換前會保存上一個任務的狀態,以便下次切換回這個任務時,能夠再次加載這個任務的狀態,從任務保存到再加載的過程就是一次上下文切換

這就像咱們同時讀兩本書,當咱們在讀一本英文的技術書籍時,發現某

 

十、什麼是線程安全

線程安全的代碼是多個線程同時執行也能工做的代碼

若是一段代碼能夠保證多個線程訪問的時候正確操做共享數據,那麼它是線程安全的

 

若是你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的,並且其餘的變量的值也和預期的是同樣的,

就是線程安全的。

或者說:一個類或者程序所提供的接口對於線程來講是原子操做或者多個線程之間的切換不會致使該接口的執行結果存在二義性,也就是說咱們不用考慮同步的問題。

十一、如何檢測死鎖?怎麼預防死鎖?

利用Java自帶工具 https://www.baidu.com/s?wd=JConsole&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd" \t "https://blog.csdn.net/wolfcode_cn/article/details/_blankJConsole.界面化查看死鎖。

利用jstack 命令檢測死鎖 jpg jstack -l pid >wenjian.txt

 

1. 破壞「不可剝奪」條件:一個進程不能得到所須要的所有資源時便處於等待狀態,等待期間他佔有的資源將被隱式的釋放從新加入到 系統的資源列表中,能夠被其餘的進程使用,而等待的進程只有從新得到本身原有的資源以及新申請的資源才能夠從新啓動,執行。

2. 破壞」請求與保持條件「:第一種方法靜態分配即每一個進程在開始執行時就申請他所須要的所有資源。第二種是動態分配即每一個進程在申請所須要的資源時他自己不佔用系統資源。

3. 破壞「循環等待」條件:採用資源有序分配其基本思想是將系統中的全部資源順序編號,將緊缺的,稀少的採用較大的編號,在申請資源時必須按照編號的順序進行,一個進程只有得到較小編號的進程才能申請較大編號的進程。

十二、Java中用到的線程調度算法是什麼

搶佔式。一個線程用完CPU以後,操做系統會根據線程優先級、線程飢餓狀況等數據算出一個總的優先級並分配下一個時間片給某個線程執行

(時間片輪轉法、優先級調度法、多級反饋隊列調度法等

 

1三、Java中如何獲取到線程dump文件

 

jmap -dump:format=b,file=F:/heamdump.out 16540」命令便可以生成

jpg jstack -l pid >wenjian.txt

1四、池技術有什麼做用,常見的池技術有哪些

起到對象複用

 

1五、用線程池有什麼好處,請談談線程池的使用場景

一、避免重複建立線程,減小在建立和 銷燬線程時所花時間,及系統的總體開銷 

二、避免系統建立大量線程而消耗系統資源 

三、用戶提交的數據可以及時獲得處理,響應速度快 

四、可以更好的監控和管理線程

常量池 線程池 數據庫鏈接池

1六、線程池的技術原理是什麼

預先啓動一些線程,線程無限循環從任務隊列中獲取一個任務進行執行,直到線程池被關閉。若是某個線程由於執行某個任務發生異常而終止,那麼從新建立一個新的線程而已。如此反覆。

1七、線程池有哪些種類,各自的使用場景是什麼?

newCachedThreadPool:

 底層:返回ThreadPoolExecutor實例,corePoolSize爲0;maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲60L;unit爲TimeUnit.SECONDS;workQueue爲SynchronousQueue(同步隊列)

 通俗:當有新任務到來,則插入到SynchronousQueue中,因爲SynchronousQueue是同步隊列,所以會在池中尋找可用線程來執行,如有能夠線程則執行,若沒有可用線程則建立一個線程來執行該任務;若池中線程空閒時間超過指定大小,則該線程會被銷燬。

 適用:執行不少短時間異步的小程序或者負載較輕的服務器

newFixedThreadPool:

 底層:返回ThreadPoolExecutor實例,接收參數爲所設定線程數量nThread,corePoolSize爲nThread,maximumPoolSize爲nThread;keepAliveTime爲0L(不限時);unit爲:TimeUnit.MILLISECONDS;WorkQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列

 通俗:建立可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;若是池中的全部線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

 適用:執行長期的任務,性能好不少

newSingleThreadExecutor:

 底層:FinalizableDelegatedExecutorService包裝的ThreadPoolExecutor實例,corePoolSize爲1;maximumPoolSize爲1;keepAliveTime爲0L;unit爲:TimeUnit.MILLISECONDS;workQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列

 通俗:建立只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

 適用:一個任務一個任務執行的場景

NewScheduledThreadPool:

 底層:建立ScheduledThreadPoolExecutor實例,corePoolSize爲傳遞來的參數,maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲0;unit爲:TimeUnit.NANOSECONDS;workQueue爲:new DelayedWorkQueue() 一個按超時時間升序排序的隊列

 通俗:建立一個固定大小的線程池,線程池內線程存活時間無限制,線程池能夠支持定時及週期性任務執行,若是全部線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構

 適用:週期性執行任務的場景

1八、線程池有哪些重要的參數?

a.核心線程數

b 最大線程數

c 線程空閒時間

c 時間單位

d 阻塞隊列大小:queueCapacity

e 任務拒絕處理器 :rejectedExceptionHandler 

1九、大家在具體的設計開發過程當中是如何設置這些重要參數的?

根據任務的特性具體方案 具體定製 參見17

20、單例的使用場景是什麼,如何實現單例

系統中只存在一個實力,一種是枚舉,還有一種私有靜態內部類

單例對象的類必須保證只有一個實例存在。許多時候整個系統只須要擁有一個的全局對象,這樣有利於咱們協調系統總體的行爲

2一、如何在Java中建立線程安全的Singleton

public class StaticSingleton {

02 private StaticSingleton(){

03 System.out.println("StaticSingleton is create");

04 }

05 private static class SingletonHolder {

06 private static StaticSingleton instance = new StaticSingleton();

07 }

08 public static StaticSingleton getInstance() {

09 return SingletonHolder.instance;

10 }

2二、11 }

2三、synchronzied關鍵詞的使用

synchronized包裹代碼塊:

I . synchronized(對象){}

II . synchronized(類名.class){}

III. synchronized(this){}

synchronized修飾方法:

I .public synchronized void memberMethod(){};

II.public static synchronized void staticMethod(){};

2四、ReentrantLock和synchronized使用的場景是什麼,機制有何不一樣

在資源競爭不是很激烈的狀況下,偶爾會有同步的情形下,synchronized是很合適的。緣由在於,編譯程序一般會盡量的進行優化

synchronize,另外可讀性很是好,無論用沒用過5.0多線程包的程序員都能理解。

ReentrantLock 類實現了 Lock ,它擁有與 synchronized 相同的併發性和內存語義,可是添加了相似輪詢鎖、定時鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭用狀況下更佳

的性能。

其實ReentrantLock是一個可重入的互斥鎖,重入鎖是一種遞歸無阻塞的同步機制。ReentrantLock由最近成功獲取鎖,尚未釋放的線程所擁有,當鎖被另外一個線程擁有時,調用lock的線程能夠成功獲取鎖。若是鎖已經被當前線程擁有,當前線程會當即返回

ReentrantLock能夠等同於synchronized使用,可是比synchronized有更強的功能、能夠提供更靈活的鎖機制、同時減小死鎖的發生機率。在確實須要一些 synchronized 所沒有的特性的時候,好比時間鎖等候、可中斷鎖等候、無塊結構鎖、多個條件變量或者輪詢鎖。 ReentrantLock 還具備可伸縮性的好處,應當在高度爭用的狀況下使用它,可是請記住,大多數 synchronized 塊幾乎歷來沒有出現過爭用,因此能夠把高度爭用放在一邊。我建議用 synchronized 開發,直到確實證實 synchronized 不合適,而不要僅僅是假設若是使用 ReentrantLock 「性能會更好」。請記住,這些是供高級用戶使用的高級工具。(並且,真正的高級用戶喜歡選擇可以找到的最簡單工具,直到他們認爲

2五、什麼是ThreadLocal變量

ThreadLocal,Thread:線程,這個毫無疑問。那Local呢?本地的,局部的。也就是說,ThreadLocal是線程本地的變量,只要是本線程內均可以使用,線程結束了,那麼相應的線程本地變量也就跟隨着線程消失了。

2六、ThreadLocal技術原理是什麼,它在架構中經常用來作什麼?

2七、java多線程有哪些常見的鎖,各自用法是什麼?

synchronized (同步)synchronized關鍵字修飾的代碼至關於數據庫上的互斥鎖。確保多個線程在同一時刻只能由一個線程處於方法或同步塊中,確保線程對變量訪問的可見和排它,得到鎖的對象在代碼結束後,會對鎖進行釋放。

       synchronzied使用方法有兩個:①加在方法上面鎖定方法,②定義synchronized塊。

 

condition (配合lock使用 相似 object.wait)Condition.await()方法至關於Object.wait()方法,而Condition.signal()方法至關於Object.notify()方法。固然它也有對應的Condition.signalAll()方法。一樣的在調用Condition.await()以後,線程佔用的鎖會被釋放。這樣在Condition.signal()方法調用的時候才獲取到鎖。

須要注意的是Condition.signal()方法調用以後,被喚醒的線程由於須要從新獲取鎖。因此須要等到調用Condition.signal()的線程釋放了鎖(調用ReentrantLock.unlock())以後才能繼續執行。

lockInterruptibly()方法比較特殊,當經過這個方法去獲取鎖時,若是線程正在等待獲取鎖,則這個線程可以響應中斷,即中斷線程的等待狀態。也就使說,當兩個線程同時經過lock.lockInterruptibly()想獲取某個鎖時,倘若此時線程A獲取到了鎖,而線程B只有在等待,那麼對線程B調用threadB.interrupt()方法可以中斷線程B的等待過程。因爲lockInterruptibly()的聲明中拋出了異常,因此lock.lockInterruptibly()必須放在try塊中或者在調用lockInterruptibly()的方法外聲明拋出InterruptedException。

ReentrantLock,意思是「可重入鎖」,ReentrantLock是惟一實現了Lock接口的類,而且ReentrantLock提供了更多的方法。

分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,這是由jvm本身控制的,咱們只要上好相應的鎖便可。若是你的代碼只讀數據,能夠不少人同時讀,但不能同時寫,那就上讀鎖;若是你的代碼修改數據,只能有一我的在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!讀寫鎖接口:ReadWriteLock,它的具體實現類爲:ReentrantReadWriteLock

2八、CountDownLatch用於多線程的什麼場景

1. ountDownLatch類。這個類是一個同步輔助類。用於一個線程等待多個操做完成以後再執行,也就是這個當前線程會一直阻塞,直到它所等待的多個操做已經完成。await方法,須要等到其餘操做先完成的那個線程調用的,先將線程休眠,直到其餘操做完成,計數器減爲0,纔會喚醒所以休眠的線程

2. countDown方法,每一個被等待的事件在完成以後調用,會將計數器減一

2九、volatile適用於高併發的什麼場景

volatile最適用一個線程寫,多個線程讀的場合。

   若是有多個線程併發寫操做,仍然須要使用鎖或者線程安全的容器或者原子變量來代替。(摘自Netty權威指南)

您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時知足下面兩個條件:

 對變量的寫操做不依賴於當前值。

 該變量沒有包含在具備其餘變量的不變式中。

30、多線程join方法用於什麼場景?

,主線程建立並啓動了子線程,若是子線程中須要進行大量的耗時運算,主線程每每將早於子線程結束以前結束,若是主線程想等待子線程執行完畢後,得到子線程中的處理完的某個數據,就要用到join方法了,方法join()的做用是等待線程對象唄銷燬;

join底層是wait方法,因此它是會釋放https://www.baidu.com/s?wd=%E5%AF%B9%E8%B1%A1%E9%94%81&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd" \t "https://blog.csdn.net/liuyifeng1920/article/details/_blank對象鎖的,而sleep在同步的方法中是不釋放對象鎖的,只有同步方法執行完畢,其餘線程才能夠執行。

3一、java多線程中讓全部子線程執行完畢的方法有哪幾種?

一、用sleep方法,讓主線程睡眠一段時間,固然這個睡眠時間是主觀的時間,是咱們本身定的,這個方法不推薦,可是在這裏仍是寫一下,畢竟是解決方法

二、使用Thread的join()等待全部的子線程執行完畢,主線程在執行,thread.join()把指定的線程加入到當前線程,能夠將兩個交替執行的線程合併爲順序執行的線程。好比在線程B中調用了線程A的Join()方法,直到線程A執行完畢後,纔會繼續執行線程B。

三、countDownLatch不可能從新初始化或者修改CountDownLatch對象內部計數器的值,一個線程調用countdown方法happen-before另一個線程調用await方法

四、同步屏障CyclicBarrier方法能夠使用reset()方法重置,因此CyclicBarrier方法能夠能處理更爲複雜的業務場景。

3二、高併發環境下的計數器如何實現?

3三、HashTable、HashMap、ConcurrentHashMap各自的技術原理和使用場景是什麼?

HashMap

實現了Map接口,實現了將惟一鍵隱射到特定值上。容許一個NULL鍵和多個NULL值。非線程安全。

HashTable

相似於HashMap,可是不容許NULL鍵和NULL值,比HashMap慢,由於它是同步的。HashTable是一個線程安全的類,它使用synchronized來鎖住整張Hash表來實現線程安全,即每次鎖住整張表讓線程獨佔。

ConcurrentHashMap

ConcurrentHashMap容許多個修改操做併發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對hash表的不一樣部分進行的修改。ConcurrentHashMap內部使用段(Segment)來表示這些不一樣的部分,每一個段其實就是一個小的Hashtable,它們有本身的鎖。只要多個修改操做發生在不一樣的段上,它們就能夠併發進行。

3四、LinkedBlockingQueue、ConcurrentLinkedQueue各自技術原理和使用場景是什麼?

 LinkedBlockingQueue是一個線程安全的阻塞隊列,基於鏈表實現,通常用於生產者與消費者模型的開發中。採用鎖機制來實現多線程同步,提供了一個構造方法用來指定隊列的大小,若是不指定大小,隊列採用默認大小(Integer.MAX_VALUE,即整型最大值)。

ConcurrentLinkedQueue是一個線程安全的非阻塞隊列,基於鏈表實現。java並無提供構造方法來指定隊列的大小,所以它是無界的。爲了提升併發量,它經過使用更細的鎖機制,使得在多線程環境中只對部分數據進行鎖定,從而提升運行效率

3五、Java中如何中止一個線程?

  使用退出標誌,使線程正常退出,也就是當run方法完成後線程終止。 

    2.  使用stop方法強行終止線程(這個方法不推薦使用,由於stop和suspend、resume同樣,也可能發生不可預料的結果)。 

1.     3.  使用interrupt方法中斷線程。

3六、Java中Semaphore是什麼?

Semaphore是用來保護一個或者多個共享資源的訪問,Semaphore內部維護了一個計數器,其值爲能夠訪問的共享資源的個數。一個線程要訪問共享資源,先得到信號量,若是信號量的計數器值大於1,意味着有共享資源能夠訪問,則使其計數器值減去1,再訪問共享資源。

若是計數器值爲0,線程進入休眠。當某個線程使用完共享資源後,釋放信號量,並將信號量內部的計數器加1,以前進入休眠的線程將被喚醒並再次試圖得到信號量。

Semaphore除了控制資源的多個副本的併發訪問控制,也能夠使用二進制信號量來實現相似synchronized關鍵字和Lock鎖的併發訪問控制功能。

3七、java多線程中有哪些併發流量控制工具類?

別爲CountDownLatch、CyclicBarrier、Semaphore和Exchanger,;

一、CountDownLatch,它是一種計數器的方式保證線程同步;它不去控制多個子線程之間的先後關係,只保證某一線程可以在這些子線程執行完成後再執行。

二、CyclicBarrier,經過設置屏障的方式使得多線程同步,可以控制多個線程在屏障處等等其餘線程也執行到屏障點,能夠實現CountDownLatch具備的功能,可是比CountDownLatch功能強大;

三、Semaphore,信號量,用於控制訪問某一公共資源的併發線程數;

四、Exchanger,用於兩個線程之間的數據交換。

3八、如何理解動態代理?

   代理模式是經常使用的java設計模式,他的特徵是代理類與委託類有一樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及過後處理消息等。代理類與委託類之間一般會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象自己並不真正實現服務,而是經過調用委託類的對象的相關方法,來提供特定的服務。簡單的說就是,咱們在訪問實際對象時,是經過代理對象來訪問的,代理模式就是在訪問實際對象時引入必定程度的間接性,由於這種間接性,能夠附加多種用途;

3九、什麼是線程安全?

若是你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的,並且其餘的變量的值也和預期的是同樣的,就是https://www.baidu.com/s?wd=%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao" \t "https://zhidao.baidu.com/question/_blank線程安全的。

40、能舉幾個不是線程安全的數據結構麼?

Hashmap 、ArrayList 、LinkedList 、TreeMap、

4一、常見的多線程數據結構有哪些,你用過其中的哪些多線程數據結構?

Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、、HashTable(子類LinkedHashMap)ConcurrentHashMap

ConcurrentLinkedQueue採用的是無鎖的方式,因此其性能在高併發中很好。

    BlockingQueue採用的是生產者消費者模式的方式進行加鎖。Blocking的具體實現有ArrayBlockingQueue和LinkedBlockingQueue

4二、多線程的常見設計模式,你用過其中的哪些設計模式

Future模式,Master-Worker模式,生產者-消費者模型 

4三、什麼是Master-Worker模式?如何實現Master-Worker模式?

Master-Worker模式是經常使用的並行計算模式。他的核心思想是系統由兩類進程協做工做:Master進程和Worker進程.Maseter負責接收和分配任務, Worker負責處理子任務。當各個Worker子進行處理完成後,會將結果返回給Master,由Msster作概括總結,好處是能將一個大任務分解成若干個小任務,並行執行,從而提升系統的吞吐量

4四、什麼是Producer-Consumer模式?如何實現Producer-Consumer模式;

在生產-消費模式中:一般由兩類線程,即若干個生產者和若干個消費者的線程。生產者負責提交用戶數據,消費者負責具體處理生產者提交的任務,在生產者和消費者之間經過共享內存緩存區進行通訊。

4五、什麼是Future模式?如何實現Future模式

Future模式相似於異步請求 

4六、多線程使用場景是什麼?

一、數據庫的數據分析(待分析的數據太多),數據遷移。

二、servlet多線程。

三、FTP下載,多線程操做文件。

四、數據庫用到的多線程。

五、分佈式計算。

六、tomcat,tomcat內部採用多線程,上百個客戶端訪問同一個WEB應用,tomcat接入後就是把後續的處理扔給一個新的線程來處理,這個新的線程最後調用咱們的servlet程序,好比doGet或者dpPost方法。

七、後臺任務:如定時向大量(100W以上)的用戶發送郵件;按期更新配置文件、任務調度(如quartz),一些監控用於按期信息採集。

八、自動做業處理:好比按期備份日誌、按期備份數據庫。

九、異步處理:如發微博、記錄日誌。

十、頁面異步處理:好比大批量數據的核對工做(有10萬個手機號碼,覈對哪些是已有用戶)。

4七、多線程有優缺點?

什麼時候使用多線程技術,什麼時候避免用它,是咱們須要掌握的重要課題。多線程技術是一把雙刃劍,在使用時須要充分考慮它的優缺點。

多線程處理能夠同時運行多個線程。因爲多線程應用程序將程序劃分紅多個獨立的任務,所以能夠在如下方面顯著提升性能: 

(1)多線程技術使程序的響應速度更快 ,由於用戶界面能夠在進行其它工做的同時一直處於活動狀態;

(2)當前沒有進行處理的任務時能夠將處理器時間讓給其它任務;

(3)佔用大量處理時間的任務能夠按期將處理器時間讓給其它任務;

(4)能夠隨時中止任務;

(5)能夠分別設置各個任務的優先級以優化性能。

 是否須要建立多個線程取決於各類因素。在如下狀況下,最適合採用多線程處理: 

(1)耗時或大量佔用處理器的任務阻塞用戶界面操做;

(2)各個任務必須等待外部資源 (如遠程文件或 Internet鏈接)。

 

一樣的 ,多線程也存在許多缺點 ,在考慮多線程時須要進行充分的考慮。多線程的主要缺點包括: 

(1)等候使用共享資源時形成程序的運行速度變慢。這些共享資源主要是獨佔性的資源 ,如打印機等。

(2)對線程進行管理要求額外的 CPU開銷。線程的使用會給系統帶來上下文切換的額外負擔。當這種負擔超過必定程度時,多線程的特色主要表如今其缺點上,好比用獨立的線程來更新數組內每一個元素。

(3)線程的死鎖。即較長時間的等待或資源競爭以及死鎖等多線程症狀。

(4)對公有變量的同時讀或寫。當多個線程須要對公有變量進行寫操做時,後一個線程每每會修改掉前一個線程存放的數據,從而使前一個線程的參數被修改;另外 ,當公用變量的讀寫操做是非原子性時,在不一樣的機器上,中斷時間的不肯定性,會致使數據在一個線程內的操做產生錯誤,從而產生莫名其妙的錯誤,而這種錯誤是程序員沒法預知的。

 

4八、假設某系統的某個接口的峯值TPS爲2w/s(其它接口的併發峯值至多爲200每秒),且該接口會保存數據至數據庫,如何提高該接口的性能?

利用多線程 將併發數改爲200;

建立一個任務隊列裏面存入要存聽任務書2.1W;建立線程2個100或1個200處理請求。若是實時,處理不來能夠設置超時返回錯誤。

4九、是否熟悉java concurrent包的內容,請講講concurrent包有哪些重要的內容?

locks部分:顯式鎖(互斥鎖和速寫鎖)相關;

atomic部分:原子變量類相關,是構建非阻塞算法的基礎;

executor部分:線程池相關;

collections部分:併發容器相關;

tools部分:同步工具相關,如信號量、閉鎖、柵欄等功能;

50、請講講併發編程的CAS理論

CAS 操做包含三個操做數 -- 內存位置、預期數值和新值。CAS 的實現邏輯是將內存位置處的數值與預期數值想比較,若相等,則將內存位置處的值替換爲新值。若不相等,則不作任何操做。

5一、請講講併發隊列和阻塞隊列

ConcurrentLinkedQueue : 是一個適用於高併發場景下的隊列,經過無鎖的方式,實現

了高併發狀態下的高性能,一般ConcurrentLinkedQueue性能好於BlockingQueue.它

是一個基於連接節點的無界線程安全隊列。該隊列的元素遵循先進先出的原則。頭是最早

加入的,尾是最近加入的,該隊列不容許null元素。

 

阻塞隊列(BlockingQueue)是一個支持兩個附加操做的隊列。

阻塞隊列經常使用於生產者和消費者的場景,生產者是往隊列裏添加元素的線程,消費者是從隊列裏拿元素的線程。阻塞隊列就是生產者存放元素的容器,而消費者也只從容器裏拿元素。

BlockingQueue即阻塞隊列,從阻塞這個詞能夠看出,在某些狀況下對阻塞隊列的訪問可能會形成阻塞。被阻塞的狀況主要有以下兩種:1. 當隊列滿了的時候進行入隊列操做2. 當隊列空了的時候進行出隊列操做

所以,當一個線程試圖對一個已經滿了的隊列進行入隊列操做時,它將會被阻塞,除非有另外一個線程作了出隊列操做;一樣,當一個線程試圖對一個空隊列進行出隊列操做時,

它將會被阻塞,除非有另外一個線程進行了入隊列操做。

在Java中,BlockingQueue的接口位於java.util.concurrent 包中(在Java5版本開始提供),由上面介紹的阻塞隊列的特性可知,阻塞隊列是線程安全的。

在新增的Concurrent包中,BlockingQueue很好的解決了多線程中,如何高效安全「傳輸」數據的問題。經過這些高效而且線程安全的隊列類。

5二、多線程yield方法使用於什麼場景?

Thread.yield()方法做用是:暫停當前正在執行的線程對象(及放棄當前擁有的cup資源),並執行其餘線程。

 

yield()作的是讓當前運行線程回到可運行狀態,以容許具備相同優先級的其餘線程得到運行機會。所以,使用yield()的

目的是讓相同優先級的線程之間能適當的輪轉執行。可是,實際中沒法保證yield()達到讓步目的,由於讓步的線程還有可能被

線程調度程序再次選中。

5三、請講講線程異步處理的原理及關鍵組件?

http://lib.csdn.net/base/javase" \o "Java SE知識庫" \t "https://www.cnblogs.com/tuojunjie/p/_blankJava平臺,實現異步調用的角色有以下三個角色:調用者、 提貨單 、真實數據,一個調用者在調用耗時操做,不能當即返回數據時,先返回一個提貨單

.而後在過一斷時間後憑提貨單來獲取真正的數據.去蛋糕店買蛋糕,不須要等蛋糕作出來(假設現作要很長時間),只須要領個提貨單就能夠了(去幹別的

事情),等到蛋糕作好了,再拿提貨單取蛋糕就能夠了。

5四、在實際項目(產品)研發過程當中,你是否有使用過多線程,和線程池,若是有,請舉例說明(要用STAR模型);

5五、什麼是多線程的原子操做?Java 中有哪些原子操做?

即不能被線程調度機制中斷的操做。原子操做不須要進行同步控制。

 

原子操做能夠是一個步驟,也能夠是多個操做步驟,可是其順序不能夠被打亂,也不能夠被切割而只執行其中的一部分,將整個操做視做一個總體是原子性的核心特徵;

原子更新基本類型

1)除long和double以外的基本類型的賦值操做

2)全部引用reference的賦值操做

3)java.concurrent.Atomic.* 包中全部類的一切操做

AtomicBoolean :原子更新布爾類型

AtomicInteger: 原子更新整型

AtomicLong: 原子更新長整型

原子更新數組

AtomicIntegerArray :原子更新整型數組裏的元素

AtomicLongArray :原子更新長整型數組裏的元素

AtomicReferenceArray : 原子更新引用類型數組的元素

AtomicBooleanArray :原子更新布爾類型數組的元素

原子更新引用類型

AtomicReference :原子更新引用類型

AtomicReferenceFieldUpdater :原子更新引用類型裏的字段

AtomicMarkableReference:原子更新帶有標記位的引用類型。能夠原子更新一個布爾類型的標記位和應用類型

原子更新字段類

AtomicIntegerFieldUpdater:原子更新整型的字段的更新器

AtomicLongFieldUpdater:原子更新長整型字段的更新器

AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整型數值與引用關聯起來,可用於原子的更新數據和數據的版本號,能夠解決使用CAS進行原子更新時可能出現的ABA問題。

5六、多線程的原子操做類的使用場景是什麼,你在項目的實際研發過程當中是否有使用過原子操做類?

原子操做能夠是一個步驟,也能夠是多個操做步驟,可是其順序不能夠被打亂,也不能夠被切割而只執行其中的一部分,將整個操做視做一個總體是原子性的核心特徵;

原子更新基本類型

 

計數器 能夠用原子操做

5七、如何在多個線程間共享數據?

若是每一個線程執行的代碼相同,能夠使用同一個Runnable對象,這個Runnable對象中有那個共享數據,例如,賣票系統就能夠這麼作。

將共享數據封裝成另一個對象,而後將這個對象逐一傳遞給各個Runnable對象,每一個線程對共享數據的操做方法也分配到那個對象身上完成,這樣容易實現針對數據進行各個操做的互斥和通訊

將Runnable對象做爲一個類的內部類,共享數據做爲這個類的成員變量,每一個線程對共享數據的操做方法也封裝在外部類,以便實現對數據的各個操做的同步和互斥,做爲內部類的各個Runnable對象調用外部類的這些方法。

5八、線程的狀態有哪些,線程狀態的使用場景是什麼?

 一、新狀態:線程對象已經建立,尚未在其上調用start()方法。

  二、可運行狀態:當線程有資格運行,但調度程序尚未把它選定爲運行線程時線程所處的狀態。當start()方法調用時,線程首先進入可運行狀態。在線程運行以後或者從阻塞、等待或睡眠狀態回來後,也返回到可運行狀態。

  三、運行狀態:線程調度程序從可運行池中選擇一個線程做爲當前線程時線程所處的狀態。這也是線程進入運行狀態的惟一一種方式。

  四、等待/阻塞/睡眠狀態:這是線程有資格運行時它所處的狀態。實際上這個三狀態組合爲一種,其共同點是:線程仍舊是活的,可是當前沒有條件運行。換句話說,它是可運行的,可是若是某件事件出現,他可能返回到可運行狀態。

五、死亡態:當線程的run()方法完成時就認爲它死去。這個線程對象也許是活的,可是,它已經不是一個單獨執行的線程。線程一旦死亡,就不能復生。若是在一個死去的線程上調用start()方法,會拋出java.lang.IllegalThreadStateException異常。

5九、有多個線程T1,T2,T3,怎麼確保它們按順序執行?

1)能夠在線程裏面加入join方法 一次等待前面的線程執行完 在執行後面的

2)用Executors.newSingleThreadExecutor();分別依次提交 開啓,這樣就執行有序了。

60、volatile變量和atomic變量有什麼不一樣?

Volatile是讓變量在全部線程中變得可見。操做時不必定保證原子性,線程安全。

Atomic是原子性,線程安全的。他的修改是sysnizied。

6一、wait/notify/notifyAll通常使用於什麼場景?

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

   當有線程調用了對象的notifyAll()方法(喚醒全部wait線程)或notify()方法(只隨機喚醒一個wait線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會去競爭該對象鎖。

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

 

6二、什麼是JVM ?

JVM是Java Virtual Machine(Javahttps://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E6%9C%BA" \t "https://baike.baidu.com/item/JVM/_blank虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。

https://baike.baidu.com/item/Java%E8%AF%AD%E8%A8%80" \t "https://baike.baidu.com/item/JVM/_blankJava語言的一個很是重要的特色就是與平臺的無關性。而使用Java虛擬機是實現這一特色的關鍵。通常的高級語言若是要在不一樣的平臺上運行,至少須要編譯成不一樣的https://baike.baidu.com/item/%E7%9B%AE%E6%A0%87%E4%BB%A3%E7%A0%81/9407934" \t "https://baike.baidu.com/item/JVM/_blank目標代碼。而引入Java語言虛擬機後,Java語言在不一樣平臺上運行時不須要從新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言https://baike.baidu.com/item/%E7%BC%96%E8%AF%91%E7%A8%8B%E5%BA%8F/8290180" \t "https://baike.baidu.com/item/JVM/_blank編譯程序只需生成在Java虛擬機上運行的目標代碼(https://baike.baidu.com/item/%E5%AD%97%E8%8A%82%E7%A0%81/9953683" \t "https://baike.baidu.com/item/JVM/_blank字節碼),就能夠在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的https://baike.baidu.com/item/%E6%9C%BA%E5%99%A8%E6%8C%87%E4%BB%A4/8553126" \t "https://baike.baidu.com/item/JVM/_blank機器指令執行。這就是Java的可以「一次編譯,處處運行」的緣由。

6三、Java中堆和棧有什麼區別?

各司其職:

最主要的區別就是棧內存用來存儲局部變量和方法調用。

而堆內存用來存儲Java中的對象。不管是成員變量,局部變量,仍是類變量,它們指向的對象都存儲在堆內存中。

獨有仍是共享:

棧內存歸屬於單個線程,每一個線程都會有一個棧內存,其存儲的變量只能在其所屬線程中可見,即棧內存能夠理解成線程的私有內存。

而堆內存中的對象對全部線程可見。堆內存中的對象能夠被全部線程訪問。

異常錯誤:

若是棧內存沒有可用的空間存儲方法調用和局部變量,JVM會拋出java.lang.StackOverFlowError。

而若是是堆內存沒有可用的空間存儲生成的對象,JVM會拋出java.lang.OutOfMemoryError。

空間大小:

棧的內存要遠遠小於堆內存,若是你使用遞歸的話,那麼你的棧很快就會充滿。若是遞歸沒有及時跳出,極可能發生StackOverFlowError問題。

你能夠經過-Xss選項設置棧內存的大小。-Xms選項能夠設置堆的開始時的大小,-Xmx選項能夠設置堆的最大值。

這就是Java中堆和棧的區別。理解好這個問題的話,能夠對你解決開發中的問題,分析堆內存和棧內存使用,甚至性能調優都有幫助。

6四、請說說jvm的基本結構?

它包括:類加載器子系統、運行時數據區、執行引擎和本地方法接口。

 

運行時數據區是JVM從操做系統申請來的堆空間和操做系統給JVM分配的棧空間的總稱。JVM爲了運行Java程序,又進一步對運行時數據區進行了劃分,劃分爲Java方法區、Java堆、Java棧、PC寄存器、本地方法棧等,這裏JVM從操做系統申請來的堆空間被劃分爲方法區和Java堆,操做系統給JVM分配的棧空間構成Java棧。

6五、堆空間的結構

 

運行時數據區中Java的方法區和Java堆(圖中顯示的是:永久、新生、老年,這是分代垃圾回收時的術語,實際上永久代和Java方法區對應,https://www.baidu.com/s?wd=%E6%96%B0%E7%94%9F%E4%BB%A3&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd" \t "https://blog.csdn.net/zhangzl4321/article/details/_blank新生代和老年代和Java堆對應),也就說Java方法區和Java堆其實都是JVM堆的一部分。JVM的棧區構成了Java的線程棧。

6六、爲什麼新生代要設置兩個survivor區,jvm的設計上有何目的?

一、Survivor的存在乎義,就是減小被送到老年代的對象,進而減小Full GC的發生,Survivor的預篩選保證,只有經歷16次Minor GC還能在新生代中存活的對象,纔會被送到老年代。

二、設置兩個Survivor區最大的好處就是解決了碎片化,永遠有一個survivor space是空的,另外一個非空的survivor space無碎片。

設計目的:

應該創建兩塊Survivor區,剛剛新建的對象在Eden中,經歷一次Minor GC,Eden中的存活對象就會被移動到第一塊survivor space S0,Eden被清空;等Eden區再滿了,就再觸發一次Minor GC,Eden和S0中的存活對象又會被複制送入第二塊survivor space S1(這個過程很是重要,由於這種複製算法保證了S1中來自S0和Eden兩部分的存活對象佔用連續的內存空間,避免了碎片化的發生)。S0和Eden被清空,而後下一輪S0與S1交換角色,如此循環往復。若是對象的複製次數達到16次,該對象就會被送到老年代中。下圖中每部分的意義和上一張圖同樣,就不加註釋了。 

6七、垃圾回收中的複製算法適用於在什麼場景下使用?

將內存分爲(大小相等)兩部分,每次只使用其中一塊進行內存分配,當內存使用完後,就出發GC,將存活的對象直接複製到另外一塊空閒的內存中,而後對當前使用的內存塊一次性清除全部,而後轉到另外一塊內存進行使用。 

優勢:簡單,高效。 

缺點:浪費內存,由於每次都有另外一塊內存空閒着。

Eden survivor 垃圾回收

6八、老年代的垃圾回收通常用什麼算法?

標記-壓縮-清理算法進行垃圾回收,將標記對象移動到堆的另外一端,同時更新對象的引用地址

一、mark_sweep_phase1: 標記活躍對象

二、mark_sweep_phase2: 計算活躍對象在壓縮完成以後的新地址

 

6九、怎麼獲取 Java 程序使用的內存?堆使用的百分比?

jhat:內存分析工具:

 

主要是對java應用程序的資源和性能進行實時的命令行監控,包括了對heap size和垃圾回收情況的監控。

 jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

option:咱們常用的選項有gc、gcutil

vmid:java進程id

interval:間隔時間,單位爲毫秒

count:打印次數

 

jmap -heap pid:查看堆使用狀況

jmap -histo pid:查看堆中對象數量和大小

jmap -dump:format=b,file=heapdump pid:將內存使用的詳細狀況輸出到文件

序列號、Class實例的數量、內存的佔用、類限定名

若是是內部類,類名的開頭會加上*,若是加上live子參數的話,如jmap -histo:live pid,這個命名會觸發一次FUll GC,只統計存活對象

70、GC回收機制?

 

7一、jmap命令是有什麼用途?jstat命令是有什麼用途?

https://www.baidu.com/s?wd=Jmap&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd" \t "_blankmap是一個能夠輸出全部內存中對象的工具,甚至能夠將VM 中的heap,以二進制輸出成文本。打印出某個java進程(使用pid)內存內的,

Jstat是JDK自帶的一個輕量級小工具。全稱「Java Virtual Machine statistics monitoring tool」,它位於java的bin目錄下,主要利用JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收情況的監控。可見,Jstat是輕量級的、專門針對JVM的工具,很是適用。

 

 

7二、有哪些常見的jvm命令,說說各自的用途是什麼?

Jps:JVM Process Status Tool,顯示指定系統內全部的HotSpot虛擬機進程

Jstat: 是用於監視虛擬機運行時狀態信息的命令,它能夠顯示出虛擬機進程中的類裝載、內存、垃圾收集、JIT編譯等運行數據。

Jmap:(JVM Memory Map)命令用於生成heap dump文件,若是不使用這個命令,還闊以使用-XX:+HeapDumpOnOutOfMemoryError參數來讓虛擬機出現OOM的時候·自動生成dump文件。

jmap不只能生成dump文件,還闊以查詢finalize執行隊列、Java堆和永久代的詳細信息,如當前使用率、當前使用的是哪一種收集器等。

jhat(JVM Heap Analysis Tool)命令是與jmap搭配使用,用來分析jmap生成的dump,jhat內置了一個微型的HTTP/HTML服務器,生成dump的分析結果後,能夠在瀏覽器中查看。在此要注意,通常不會直接在服務器上進行分析,由於jhat是一個耗時而且耗費硬件資源的過程,通常把服務器生成的dump文件複製到本地或其餘機器上進行分析。

jstack用於生成java虛擬機當前時刻的線程快照。線程快照是當前java虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的緣由,如線程間死鎖、死循環、請求外部資源致使的長時間等待等。 線程出現停頓的時候經過jstack來查看各個線程的調用堆棧,就能夠知道沒有響應的線程到底在後臺作什麼事情,或者等待什麼資源。 若是java程序崩潰生成core文件,jstack工具能夠用來得到core文件的java stack和native stack的信息,從而能夠輕鬆地知道java程序是如何崩潰和在程序何處發生問題。另外,jstack工具還能夠附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息, 若是如今運行的java程序呈現hung的狀態,jstack是很是有用的。

info(JVM Configuration info)這個命令做用是實時查看和調整虛擬機運行參數。

以前的jps -v口令只能查看到顯示指定的參數,若是想要查看未被顯示指定的參數的值就要使用jinfo口令

7三、、GC有哪些算法(*****)

引用計數,沒有被Java採用

標記-清除

標記-壓縮 標記-整理算法

複製算法 新生代

 

7四、、什麼是線程中斷。tips: stop the world,簡稱STW,參考billy1.GC算法與種類

Java中一種全局暫停的現象

全局停頓,全部Java代碼中止,native代碼能夠執行,但不能和JVM交互

 

 

7五、MGC、FGC分別是什麼意思,它們在什麼狀況下會發生

,YG用來放新產生的對象,通過幾回回收還沒回收掉的對象往OG中移動,對YG進行垃圾回收又叫作MinorGC,對 OG垃圾回收又叫MajorGC,.

一、當eden滿了,觸發young GC;

2.young GC作2件事:一,去掉一部分沒用的object;二,把老的還被引用的object發到survior裏面,等下幾回GC之後,survivor再放到old裏面。

3.當old滿了,觸發full GC。full GC很消耗內存,把old,young裏面大部分垃圾回收掉。這個時候用戶線程都會被block。

 

7六、、請講講jvm的分代,爲何要分代,jvm分代有什麼好處?

虛擬機中的共劃分爲三個代:年輕代(Young Generation)、年老點(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關係不大。年輕代和年老代的劃分是對垃圾收集影響比較大的。

利用對象存活的生命不一樣。利用的算法不一樣。

全部新生成的對象首先都是放在年輕代的。年輕代的目標就是儘量快速的收集掉那些生命週期短的對象。年輕代分三個區。一個Eden區,兩個Survivor區(通常而言)。大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被複制到Survivor區(兩個中的一個),當這個Survivor區滿時,此區的存活對象將被複制到另一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區複製過來的而且此時還存活的對象,將被複制「年老區(Tenured)」。須要注意,Survivor的兩個區是對稱的,沒前後關係,因此同一個區中可能同時存在從Eden複製過來 對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。並且,Survivor區總有一個是空的。同時,根據程序須要,Survivor區是能夠配置爲多個的(多於兩個),這樣能夠增長對象在年輕代中的存在時間,減小被放到年老代的可能。

 

7七、、你知道哪些jvm調優工具麼?

uptime 系統時間 運行時間 鏈接數 1,5,15分鐘內的系統平均負載

top

vmstat能夠統計系統的CPU,內存,swap,io等狀況

pidstat細緻觀察進程

任務管理器

Perfmon

Process Explorer

pslist

 

 

7八、、在jvm中,年輕代如何向老年代轉變的?年輕代向老年代轉換的重要參數是什麼?

當eden滿了,觸發young GC;

2.young GC作2件事:一,去掉一部分沒用的object;二,把老的還被引用的object發到survior裏面,等下幾回GC之後,survivor再放到old裏面。

3.當old滿了,觸發full GC。full GC很消耗內存,把old,young裏面大部分垃圾回收掉。這個時候用戶線程都會被block。

 

-Xms 和 -Xmx (-XX:InitialHeapSize 和 -XX:MaxHeapSize):指定JVM初始佔用的堆內存和最大堆內存。JVM也是一個軟件,也必需要獲取本機的物理內

-XX:MaxTenuringThreshold= 設置熬過年輕代多少次收集後移入老人區,CMS中默認爲0,熬過第一次GC就轉入,能夠用-XX:+PrintTenuringDistribution 查看

調用16次

7九、、直接內存使用場景是什麼,使用直接內存可能會存在什麼問題?tips

 

80、、堆內存有哪些重要參數?

默認空餘堆內存小於40%時,JVM就會增大堆直到-Xmx的最大限制,能夠由 -XX:MinHeapFreeRatio=指定。 

默認空餘堆內存大於70%時,JVM會減小堆直到-Xms的最小限制,能夠由 -XX:MaxHeapFreeRatio=指定。 

服務器通常設置-Xms、-Xmx相等以免在每次GC後調整堆的大小,因此上面的兩個參數沒啥用。 

oung(Nursery):年輕代 

研究代表大部分對象都是朝生暮死,隨生隨滅的。因此對於年輕代在GC時都採起復制收集算法,具體算法參考下面的描述; 

Young的默認值爲4M,隨堆內存增大,約爲1/15,JVM會根據狀況動態管理其大小變化。 

Young裏面又分爲3 個區域,一個Eden,全部新建對象都會存在於該區,兩個Survivor區,用來實施複製算法。 

-XX:NewRatio= 參數能夠設置Young與Old的大小比例,-server時默認爲1:2,但實際上young啓動時遠低於這個比率?若是信不過JVM,也能夠用 -Xmn硬性規定其大小,有文檔推薦設爲Heap總大小的1/4。 

-XX:SurvivorRatio= 參數能夠設置Eden與Survivor的比例,默認爲32。Survivio大了會浪費,小了的話,會使一些年輕對象潛逃到老人區,引發老人區的不安,但這個參數對性能並不過重要。 

 

Old(Tenured):年老代 

年輕代的對象若是可以挺過數次收集,就會進入老人區。老人區使用標記整理算法。由於老人區的對象都沒那麼容易死的,採用複製算法就要反覆的複製對象,很不合算,只好採用標記清理算法,但標記清理算法其實也不輕鬆,每次都要遍歷區域內全部對象,因此仍是沒有免費的午飯啊。 

-XX:MaxTenuringThreshold= 設置熬過年輕代多少次收集後移入老人區,CMS中默認爲0,熬過第一次GC就轉入,能夠用-XX:+PrintTenuringDistribution 查看。 

 

Permanent:持久代 

裝載Class信息等基礎數據,默認64M,若是是類不少不少的服務程序,須要加大其設置 -XX:MaxPermSize=,不然它滿了以後會引發fullgc()或Out of Memory。 注意Spring,Hibernate這類喜歡AOP動態生成類的框架須要更多的持久代內存。通常狀況下,持久代是不會進行GC的,除非經過 -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled進行強制設置。 

8一、如何設置堆大小,是否有一些經驗值?

JVM 中最大堆大小有三方面限制:相關操做系統的數據模型(32-bt仍是64-bit)限制;系統的可用虛擬內存限制;系統的可用物理內存限制。32位系統 下,通常限制在1.5G~2G;64爲操做系統對內存無限制。我在Windows Server 2003 系統,3.5G物理內存,JDK5.0下測試,最大可設置爲1478m。 

 

典型JVM參數設置: 

 

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k 

 

-Xmx3550m:設置JVM最大可用內存爲3550M。 

 

-Xms3550m:設置JVM促使內存爲3550m。此值能夠設置與-Xmx相同,以免每次垃圾回收完成後JVM從新分配內存。 

 

-Xmn2g:設置年輕代大小爲2G。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代通常固定大小爲64m,因此增大年輕代後,將會減少年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。 

 

-Xss128k:設置每一個線程的堆棧大小。JDK5.0之後每一個線程堆棧大小爲1M,之前每一個線程堆棧大小爲256K。更具應用的線程所需內存大小進行 調整。在相同物理內存下,減少這個值能生成更多的線程。可是操做系統對一個進程內的線程數仍是有限制的,不能無限生成,經驗值在 3000~5000 左右。 

 

java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 

 

-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置爲4,則年輕代與年老代所佔比值爲1:4,年輕代佔整個堆棧的1/5 

 

-XX:SurvivorRatio=4:設置年輕代中Eden區與Survivor區的大小比值。設置爲4,則兩個Survivor區與一個 Eden區的比值爲2:4,一個Survivor區佔整個年輕代的1/6 

 

-XX:MaxPermSize=16m:設置持久代大小爲16m。 

 

-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。若是設置爲0的話,則年輕代對象不通過Survivor區,直接進入年老代。 對於年老代比較多的應用,能夠提升效率。若是將此值設置爲一個較大值,則年輕代對象會在Survivor區進行屢次複製,這樣能夠增長對象再年輕代的存活 時間,增長在年輕代即被回收的概論。 

 

8二、如何打印JVM日誌?

-XX:+PrintGCDetails -Xloggc:../logs/gc.log -XX:+PrintGCTimeStamps

8三、請介紹常見的jvm參數

-XX:+PrintGCTimeStamps:

 

打印這次垃圾回收距離jvm開始運行的所耗時間

 

-XX:+PrintGCDeatils

 

打印垃圾回收的細節信息

 

-Xloggc:<filename>

 

將垃圾回收信息輸出到指定文件

 

-XX:+PrintGCDateStamps

 

須要打印日曆形式的時間戳選項

 

-XX:+PrintGCApplicationStoppedTime

 

-XX:+PrintGCApplicationConcurrentTime

 

打印應用程序因爲執行VM安全點操做而阻塞的時間以及兩個安全點操做之間應用程序的運行時間

 

-XX:+PrintSafepointStatistics

 

能夠將垃圾回收的安全點與其餘的安全點區分開

 -XX:+UseSerialGC:在新生代和老年代使用串行收集器

 -XX:SurvivorRatio:設置eden區大小和survivior區大小的比例

 -XX:NewRatio:新生代和老年代的比

 -XX:+UseParNewGC:在新生代使用並行收集器

 -XX:+UseParallelGC :新生代使用並行回收收集器

 -XX:+UseParallelOldGC:老年代使用並行回收收集器

 -XX:ParallelGCThreads:設置用於垃圾回收的線程數

 -XX:+UseConcMarkSweepGC:新生代使用並行收集器,老年代使用CMS+串行收集器

 -XX:ParallelCMSThreads:設定CMS的線程數量

 -XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少後觸發

 -XX:+UseCMSCompactAtFullCollection:設置CMS收集器在完成垃圾收集後是否要進行一次內存碎片的整理

 -XX:CMSFullGCsBeforeCompaction:設定進行多少次CMS垃圾回收後,進行一次內存壓縮

 -XX:+CMSClassUnloadingEnabled:容許對類元數據進行回收

 -XX:CMSInitiatingPermOccupancyFraction:當永久區佔用率達到這一百分比時,啓動CMS回收

 -XX:UseCMSInitiatingOccupancyOnly:表示只在到達閥值的時候,才進行CMS回收

 

8四、CMS收集器有什麼特色?

儘量下降停頓

會影響系統總體吞吐量和性能

好比,在用戶線程運行過程當中,分一半CPU去作GC,系統性能在GC階段,反應速度就降低一半

清理不完全

由於在清理階段,用戶線程還在運行,會產生新的垃圾,沒法清理

由於和用戶線程一塊兒運行,不能在空間快滿時再清理

 

8五、G1收集器有什麼特色?

並行於併發:G1能充分利用CPU、多核環境下的硬件優點,使用多個CPU(CPU或者CPU核心)來縮短stop-The-World停頓時間。部分其餘收集器本來須要停頓Java線程執行的GC動做,G1收集器仍然能夠經過併發的方式讓java程序繼續執行。

 

二、分代收集:雖然G1能夠不須要其餘收集器配合就能獨立管理整個GC堆,可是仍是保留了分代的概念。它可以採用不一樣的方式去處理新建立的對象和已經存活了一段時間,熬過屢次GC的舊對象以獲取更好的收集效果。

 

三、空間整合:與CMS的「標記--清理」算法不一樣,G1從總體來看是基於「標記整理」算法實現的收集器;從局部上來看是基於「複製」算法實現的。

 

四、可預測的停頓:這是G1相對於CMS的另外一個大優點,下降停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能創建可預測的停頓時間模型,能讓使用者明確

 

8六、垃圾回收器有哪些?

串行垃圾回收器(Serial Garbage Collector)

並行垃圾回收器(Parallel Garbage Collector)

併發標記掃描垃圾回收器(CMS Garbage Collector)

G1垃圾回收器(G1 Garbage Collector)

 

8七、java內存模型

一、主內存和工做內存

    (1)全部變量均存儲在主內存(虛擬機內存的一部分)

    (2)每一個線程都對應着一個工做線程,主內存中的變量都會複製一份到每一個線程的本身的工做空間,線程對變量的操做都在本身的工做內存中,操做完成後再將變量更新至主內存;

    (3)其餘線程再經過主內存來獲取更新後的變量信息,即線程之間的交流經過主內存來傳遞

Note:JMM的空間劃分和JVM的內存劃分不同,非要對應的話,關係以下:

    (1)JMM的主內存對應JVM中的堆內存對象實例數據部分

    (2)JMM的工做內存對應JVM中棧中部分區域

8八、什麼是類加載器,類加載器有哪些,類加載器的加載順序是什麼?

類加載器是一個用來加載類文件的類。Java源代碼經過javac編譯器編譯成類文件。而後JVM來執行類文件中的字節碼來執行程序。類加載器負責加載文件系統、網絡或其餘來源的類文件。有三種默認使用的類加載器:Bootstrap類加載器、Extension類加載器和System類加載器(或者叫做Application類加載器)。

 

1)Bootstrap類加載器 – JRE/lib/rt.jar

2) Extension類加載器 – JRE/lib/ext或者java.ext.dirs指向的目錄

3) Application類加載器 – CLASSPATH環境變量, 由-classpath或-cp選項定義,或者是JAR中的Manifest的classpath屬性定義.

VM並非把全部的類一次性所有加載到JVM中的,也不是每次用到一個類的時候都去查找,對於JVM級別的類加載器在啓動時就會把默認的JAVA_HOME/lib裏的class文件加載到JVM中,由於這些是系統經常使用的類,對於其餘的第三方類,則採用用到時就去找,找到了就緩存起來的,下次再用到這個類的時候就能夠直接用緩存起來的類對象了,ClassLoader之間也是有父子關係的,沒個ClassLoader都有一個父ClassLoader,在加載類時ClassLoader與其父ClassLoader的查找

8九、簡述java內存分配與回收策略

一、 當eden滿了,觸發young GC;

2.young GC作2件事:一,去掉一部分沒用的object;二,把老的還被引用的object發到survior裏面,等下幾回GC之後,survivor再放到old裏面。

3.當old滿了,觸發full GC。full GC很消耗內存,把old,young裏面大部分垃圾回收掉。這個時候用戶線程都會被block。

 

•Tips:eden、Sruvivor、老年代、永久代(元空間)

90、JDK1.8以後Perm Space有哪些變更? MetaSpace大小默認是無限的麼? 仍是大家會經過什麼方式來指定大小?

一、 JDK 1.8後用元空間替代了 Perm Space;字符串常量存放到堆內存中。

二、 MetaSpace大小默認沒有限制,通常根據系統內存的大小。JVM會動態改變此值。

三、 -XX:MetaspaceSize:分配給類元數據空間(以字節計)的初始大小(Oracle邏輯存儲上的初始高水位,the initial high-water-mark)。此值爲估計值,MetaspaceSize的值設置的過大會延長垃圾回收時間。垃圾回收事後,引發下一次垃圾回收的類元數據空間的大小可能會變大。

四、 -XX:MaxMetaspaceSize:分配給類元數據空間的最大值,超過此值就會觸發Full GC,此值默認沒有限制,但應取決於系統內存的大小。JVM會動態地改變此值。

 

9一、Perm Space中保存什麼數據?會引發OutOfMemory嗎?

加載class文件。

會引發,出現異常能夠設置 -XX:PermSize 的大小。JDK 1.8後,字符串常量不存放在永久帶,而是在堆內存中,JDK8之後沒有永久代概念,而是用元空間替代,元空間不存在虛擬機中,二是使用本地內存。

詳細查看Java8內存模型—永久代(PermGen)和元空間(Metaspace)

 

9二、java類加載全過程,從架構角度理解,類加載和反射、動態代理有什麼關係?

 

9三、簡述java類加載機制?tips:看ClassLoader源碼講解類加載機制,理解記憶

 

加載----驗證----準備----解析-----初始化----使用-----卸載

9四、GC收集器有哪些?CMS收集器與G1收集器的特色

串行垃圾回收器(Serial Garbage Collector)

並行垃圾回收器(Parallel Garbage Collector)

併發標記掃描垃圾回收器(CMS Garbage Collector)

G1垃圾回收器(G1 Garbage Collector)

 

9五、類加載器雙親委派模型機制,「雙親委派」中的雙親是什麼意思?tips:演示ClassLoaderTest2,講解雙親委派流程圖

若是一個類加載器收到類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父類加載器完成。每一個類加載器都是如此,只有當父加載器在本身的搜索範圍內找不到指定的類時(即ClassNotFoundException),子加載器纔會嘗試本身去加載。

9六、什麼狀況下會出現永久代內存溢出,如何解決此類問題?

生成大量的類,增大Perm區 容許Class回收

9七、什麼狀況下會出現堆內存溢出,如何解決此類問題?

佔用大量堆空間,直接溢出

增大堆空間,及時釋放內存

9八、什麼狀況下會出現直接內存溢出,如何解決此類問題?

ByteBuffer.allocateDirect()沒法從操做系統得到足夠的空間

解決方法:減小堆內存 有意觸發GC

 

9九、什麼狀況下會出現過多線程致使內存溢出的問題,如何解決此類問題?

多線程 沒有釋放內存

– 一、OOM因爲保存多線程過多引發,能夠考慮增長堆大小

– 2. 若是應用容許,縮短多線程的過時時間,使得session能夠及時過時,並回收

 

100、什麼狀況下會出現CPU使用率太高的問題,如何解決此類問題?

多線程競爭資源,多線程上下文切換太頻繁

合理設置線程最大開啓數量,併發數量

相關文章
相關標籤/搜索