1. 程式人生 > >Java面經總結

Java面經總結

執行緒安全

1.什麼是不安全?

 1.1 不同執行緒,對同一資源的訪問或修改。
 1.2 原子性   JVM規範定義了執行緒對主存的操作指令:read,load,use,assign,store,write
 1.3 可見性------------------------------------------------volatile,final,synchronized,
 1.4 有序性-------------read-load,從主存載入資料到執行緒自己的工作記憶體中,即保留一個副本,assign,修改之後, 變數副本會同步到主儲存區(store- write),何時同步不一定,導致最後在記憶體中的值不是想象中的。

2.為什麼會產生?

 1. CPU快取記憶體
 2、主記憶體

3.如何避免?

1.強同步:synchronized 關鍵字。 當一段程式碼會修改共享變數,這一段程式碼成為互斥區或臨界區,用synchronized標識起來,共享物件作為鎖,否則沒有意義。

     每個鎖物件都有兩個佇列,一個是就緒佇列,一個是阻塞佇列,就緒佇列儲存了將要獲得鎖的執行緒,阻塞佇列儲存了被阻塞的執行緒,當一個被執行緒被喚醒 (notify)後,才會進入到就緒佇列,等待cpu的排程

一個執行緒執行臨界區程式碼過程如下:
1 獲得同步鎖
2 清空工作記憶體
3 從主存拷貝變數副本到工作記憶體
4 對這些變數計算
5 將變數從工作記憶體寫回到主存
6 釋放鎖

2.生產者/消費者模式

      lock.wait   -----釋放鎖,
      lock.notify  ----通知lock中阻塞佇列裡面的某個執行緒,進入就緒佇列。
      lcok.notifyAll ---通知所有阻塞佇列裡的執行緒。


    3.volitle
      對變數修改回寫到記憶體,相當於 (store- write)
       防止指令重排

    4.共享物件不可變

     5.原子操作,原子類,底層CAS實現,但是會導致快取一致性流量,bus風暴,效能降低
            MESI協議實現,

底層實現:

 1.read,load,assign,use,store,write (底層原子操作)
 2.lock,unlock.開放api給使用者用,位元組碼為monitorenter,monitorexit   (Syncronized 關鍵字的底層)
   其實是物件頭,包含一個鎖的位置:

物件頭:

各種鎖:

1. ReentrantLock
在同步競爭不激烈時用synchronized,激烈時用ReentrantLock
 ReentrantLock提供了lockInterruptibly()方法可以優先考慮響應中斷,而不是像synchronized那樣不響應interrupt()操作
同一個執行緒,持有鎖,可以重新獲取該鎖,即重進入,避免了死鎖,內部實現有一個計數器和一個標誌位,標誌佔有的執行緒。
需要手動釋放鎖

2.synchronized + 內部鎖,或叫互斥鎖,會阻塞或等待,直到獲取鎖,無法重進入,產生死鎖
     +static 類鎖


3.公平鎖,非公平鎖
          公平鎖是指多個執行緒在等待同一個鎖時,必須按照申請鎖的先後順序來一次獲得鎖。
4.自旋鎖
      執行緒執行一個忙迴圈(自旋),等待其他執行緒釋放鎖。
5.其他
![這裡寫圖片描述](https://img-blog.csdn.net/20160912192430196)

併發工具

一.CountDownLatch用法

await()
await(long timeout,TimeUnit unit)
countDown();
二.CyclicBarrier用法

await()
await(long timeout,TimeUnit unit)
   第一個版本比較常用,用來掛起當前執行緒,直至所有執行緒都到達barrier狀態再同時執行後續任務;
  第二個版本是讓這些執行緒等待至一定的時間,如果還有執行緒沒有到達barrier狀態就直接讓到達barrier的執行緒執行後續任務。
三.Semaphore用法

1
2
3
4
public void acquire() throws InterruptedException {  }     //獲取一個許可
public void acquire(int permits) throws InterruptedException { }    //獲取permits個許可
public void release() { }          //釋放一個許可
public void release(int permits) { }    //釋放permits個許可

控制資源能夠被多少執行緒訪問,類似於鎖。

class 載入

雙親委派模型的工作流程是:如果一個類載入器收到了類載入的請求,它首先不會自己去嘗試載入這個類,而是把請求委託給父載入器去完成,依次向上,因此,所有的類載入請求最終都應該被傳遞到頂層的啟動類載入器中,只有當父載入器在它的搜尋範圍中沒有找到所需的類時,即無法完成該載入,子載入器才會嘗試自己去載入該類。

c++——-> bootstrap classloader ———->extension classloader —-> application classloader ——–>selfdefined classloader

垃圾回收

這裡寫圖片描述

1. new Object --> eden , if not enough ---> YoungGC(Minor GC)
2. Survivor Mem not enough ---> YoungGC(Major GC    : Old Generation)
3. Old Generation Mem not enough ---> Full GC  (Old: CMS)

引用演算法:

引用分類:強,軟,弱,虛

1.引用計數, 存在迴圈引用
2.可達性分析演算法,即判斷一個物件能否到達GC-roots,GC-roots:
虛擬機器棧(棧幀中的本地變量表)中引用的物件。
方法區中類靜態屬性引用的物件。
方法區中常量引用的物件。
本地方法棧中JNI(即一般說的Native方法)引用的物件。
垃圾收集演算法:

1.標記-清除  ,直接清除當前位置。
2.複製演算法   即複製到另一半,然後回收另一半,一塊大eden區,兩塊小survivor區,將eden區中存活的複製到一塊空的survivor區,清理eden和第一個survivor
3.標記-整理,然所有存活物件移動到另一端,清除另一端。
4.分代收集

5.hot-spot的實現:

          各個收集器。採用不同的垃圾收集演算法
          5.1 serial 收集器,單執行緒,新生代收集器,標記-整理
          5.2 ParNew,多執行緒的serial。
          5.3 Parallel Scavenge,新生代,複製演算法。
          5.4 serial-old
          5.5 ParalleOld
          5.6 CMS,很短暫的停頓。不會stop the world,標記-清除

eden----> survivor--->old---->perm
年齡,大物件,往後放

6.G1收集器,牛逼,即 將jvm的堆區,劃分為大小相等的region,remembered Set (referrence counting)

分為以下4各階段:

初始標記(GCroots)
併發標記
最終標記
篩選回收
1 .分代收集:仍然有分代的概念,不需要其他收集器配合,獨立管理整個GC堆。
2 .空間整合:從整體看,是基於“標記-整理”演算法實現的,從區域性(兩個Region之間)看是基於“復 制”演算法的。在執行期間不會產生記憶體碎片。
3 .可預測的停頓:G1跟蹤各個Region裡垃圾堆積值的價值大小,維護一個優先順序佇列,每次根據允許 的時間,優先回收價值最大的Region。(這也是Garbage First的由來)

虛擬機器GC引數設定

http://unixboy.iteye.com/blog/174173
-Xms   
-Xmx   JVM 最大記憶體
-Xmn   年輕代大小

-XX:SuvirorRatio=8  eden:survivor = 8:1
-XX:PretenureSizeThreshold   設定大物件閾值,超過,則直接分配到老年代 只對 parnew 和Serail 收集器有效
-XX:MaxPretenuringThreshold 設定晉升old的閾值  即age的max

-XX:+UseParNewGC:
-XX:+UseG1GC

eden --> survivor age:1
minor GC, age ++
if age >= 15 ----> Old Generation

Class:

這裡寫圖片描述

1.Magic Num :0xCAFFEBABE
2.constant_pool :

    1. literal
    2. reference name

底層進階:

執行緒實現

1.使用核心執行緒實現(KLT)。由核心分配,核心Scheduler排程。 但一般用LWP(輕量級程序),即KLT的一種介面。(user mode ,kernel mode切換消耗資源)

這裡寫圖片描述

2.使用使用者執行緒實現

這裡寫圖片描述

3.LWP和使用者執行緒混合
這裡寫圖片描述
SunJdk中用LWP(win,linux)

執行緒排程(java,搶佔式)

這裡寫圖片描述

常見集合原理原始碼

這裡寫圖片描述

Map系: HashMap,LinkedHashMap,TreeMap, WeakHashMap, EnumMap,ConcurrentHashMap

List系:ArrayList, LinkedList, Vector, Stack

Set系:HashSet, LinkedHashSet, TreeSet