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 關鍵字的底層)
   其實是對象頭,包含一個鎖的位置:

對象頭:

http://blog.csdn.net/hsuxu/article/details/9472371
這裏寫圖片描述
包含,鎖的升級,可升不可降

各種鎖:

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