一、string爲何不可繼承?html
答:由於string是用final修飾的不可變類,不能夠被繼承;java
爲何要用final修飾?android
答:安全,設計者將string設爲共享的,子類不能夠修改,所以設置爲final;web
效率,共享的效率更高;算法
String、StringBuffer和StringBuilder區別數據庫
答:運行速度StringBuilder>StringBuffer>String,String爲字符串常量,一旦建立對象後不可更改;然後者是可更改的;編程
線程安全上StringBuffer是線程安全的,StringBuilder是非線程安全的。跨域
二、怎樣減小線程的上下文切換?數組
答:減小併發線程數,儘可能使用無鎖編程,CAS算法瀏覽器
什麼是CAS算法?
答:compare and swap意思是先比較舊的預期值和原來內存中存儲的值相等,再更改成目標值,是一種樂觀鎖,適用於讀多寫少的狀況,效率較高,只有極少的狀況會發生衝突
CAS會有ABA問題應怎麼解決?
答:ABA問題是指舊的預期值被更改成和原來內存中存儲的值相等,已經發生過一次更改,這種狀況能夠經過版本號(AtomicStampedReference)、時間戳來解決,比較最初獲取的版本號和更改前獲取的版本號是否一致,一致則更改,更改後都將版本號+1
三、說下volatile關鍵字的做用?
答:可見性:當多個線程共同訪問同一變量,當其中一個線程修改了該變量,其餘線程都能馬上看到修改的值
有序性:防止指令重排序,程序執行順序按當前代碼順序執行
注:指令重排序不會影響單個線程的執行,但會影響多個線程併發執行的結果
https://www.cnblogs.com/dolphin0520/p/3920373.html
內存屏障會提供3個功能:
1)它確保指令重排序時不會把其後面的指令排到內存屏障以前的位置,也不會把前面的指令排到內存屏障的後面;即在執行到內存屏障這句指令時,在它前面的操做已經所有完成;
2)它會強制將對緩存的修改操做當即寫入主存;
3)若是是寫操做,它會致使其餘CPU中對應的緩存行無效。
volatile能夠保證原子性嗎?
答:不是,兩個線程同時從內存中讀取變量的值i=10到本身的工做內存,線程a和線程b同時作自增操做+1,寫入工做內存,再寫入主內存,兩個線程分別自增一次,但主內存中的結果只增長1,所以volatile不保證原子性
四、描述下java內存模型
答:Java內存模型規定全部的變量都是存在主存當中,每一個線程都有本身的工做內存。線程對變量的全部操做都必須在工做內存中進行,而不能直接對主存進行操做。而且每一個線程不能訪問其餘線程的工做內存。
五、描述下happens-before原則(先行發生原則)
答:Java內存模型具有一些先天的「有序性」
六、ThreadLocal 原理
定義:線程局部變量,爲每個線程都提供了一份變量副本,每個線程均可以隨意修改本身的變量副本,而不會對其餘線程產生影響;
實現:在ThreadLocal類中有一個靜態內部類ThreadLocalMap(其相似於Map),用鍵值對的形式存儲每個線程的變量副本,ThreadLocalMap中元素的key爲當前ThreadLocal對象,而value對應線程的變量副本,每一個線程可能存在多個ThreadLocal。
應用:採用了「以空間換時間」的方式,解決多線程數據共享問題,實際過程當中應用到了數據庫鏈接。
問題:ThreadLocal有可能產生內存泄漏,由於map中的key弱引用指向ThreadLocal,當把threadlocal實例置爲null之後,沒有任何強引用指向threadlocal實例,因此threadlocal將會被gc回收. 可是,咱們的value卻不能回收,由於存在一條從current thread鏈接過來的強引用。
七、synchronized鎖怎麼實現的?
答:synchronized鎖存在Java對象頭裏,每個被鎖住的對象都會和一個monitor對象關聯;
執行monitorenter獲取鎖,讀取monitor對象的count字段,count==0,則獲取鎖成功且count+1;
執行monitorexit指令時將count-1,若count==0,則釋放鎖;
synchronized爲何是重量級鎖?
答:重量級鎖經過對象內部的監視器(monitor)實現,其中monitor的本質是依賴於底層操做系統的Mutex Lock實現,操做系統實現線程之間的切換須要從用戶態到內核態的切換,切換成本很是高。
八、Lock鎖怎麼實現的?
ReentrantLock是基於AQS實現的,AQS的基礎是CAS
AbstractQueuedSynchronizer,簡稱AQS,基於volatile int state +FIFO隊列(雙端隊列)實現的,
ReentrantLock中有一個抽象類Sync,根據傳入構造方法的布爾型參數實例化出Sync的實現類FairSync和NonfairSync,並重寫tryAcquire(int arg)和tryRelease(int arg)兩個方法。
lock()利用CAS去判斷state是否是0,若是state=0,則獲取鎖,state設爲1並將當前線程設爲主;
若是state非0,執行acquire()->tryAcquire()->(非公平鎖)若是state=0,CAS嘗試獲取鎖,若加鎖成功state設爲1並將當前線程設爲主,
state非0,判斷當前owner是不是當前線程,若是是,state+1,返回true,若是不屬於當前線程,返回false,則添加FIFO等待隊列隊尾。
(公平鎖)若是state=0,hasQueuedPredecessors()判斷當前是否有等待的線程, 若是沒有使用CAS嘗試獲取鎖,若加鎖成功state設爲1並將當前線程設爲主,
state非0,判斷當前owner是不是當前線程,若是是,state+1,返回true,若是不屬於當前線程,返回false,則添加FIFO等待隊列隊尾。
ReentrantLock獲取鎖定與三種方式:
a) lock(), 若是獲取了鎖當即返回,若是別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖;
b) tryLock(), 若是獲取了鎖當即返回true,若是別的線程正持有鎖,當即返回false;
c)tryLock(long timeout,TimeUnit unit),若是獲取了鎖定當即返回true,若是別的線程正持有鎖,會等待參數給定的時間,在等待的過程當中,若是獲取了鎖定,就返回true,若是等待超時,返回false;
d)lockInterruptibly():若是獲取了鎖定當即返回,若是沒有獲取鎖,當前線程處於休眠狀態,直到獲取鎖,或者當前線程被別的線程中斷;
九、synchronized和Lock什麼區別?
類別 | synchronized | Lock |
---|---|---|
存在層次 | Java的關鍵字,在jvm層面上 | 經過代碼實現,是一個類 |
鎖的釋放 | 會自動釋放鎖定(代碼執行完成或者出現異常) | 不會主動釋放,必須將unLock()放到finally{}中 |
鎖的獲取 | 假設A線程得到鎖,B線程等待。若是A線程阻塞,B線程會一直等待 | 分狀況而定,Lock有多個鎖獲取的方式,具體下面會說道,大體就是能夠嘗試得到鎖,線程能夠不用一直等待 |
鎖狀態 | 沒法判斷 | 能夠判斷 |
鎖類型 | 可重入,不可中斷,非公平 | 可重入,可中斷,可公平(二者皆可) |
性能 | 少許同步 | 大量同步 |
十、線程池有哪幾種?
答:Java經過Executors提供四種線程池,分別爲:
一、newCachedThreadPool:建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。(線程最大併發數不可控制)SynchronousQueue
二、newFixedThreadPool:建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。LinkedBlockingQueue
三、newScheduledThreadPool:建立一個定長線程池,支持定時及週期性任務執行。
四、newSingleThreadExecutor:建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。LinkedBlockingQueue
線程池參數有哪些?
答:ThreadPoolExecutor構造方法
public ThreadPoolExecutor(int corePoolSize,//核心線程池大小
int maximumPoolSize,//最大線程池大小
long keepAliveTime,//線程池中超過corePoolSize數目的空閒線程最大存活時間;能夠allowCoreThreadTimeOut(true)成爲核心線程的有效時間
TimeUnit unit,//keepAliveTime的時間單位
BlockingQueue<Runnable> workQueue,//阻塞任務隊列
ThreadFactory threadFactory,//線程工廠
RejectedExecutionHandler handler) {//當提交任務數超過maxmumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理
線程池的工做過程?
答:1.當線程池小於corePoolSize時,新提交任務將建立一個新線程執行任務,即便此時線程池中存在空閒線程;
2.當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行;
3.當workQueue已滿,且當前線程數大於corePoolSize且小於maximumPoolSize時,新提交任務會建立新線程執行任務;
4.當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理;
5.當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程;
6.當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉;
線程池拒絕策略有幾種?
答:ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,可是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
線程池相關的幾個隊列:
答:ArrayBlockingQueue, 一個由數組結構組成的有界阻塞隊列fifo;默認狀況下不保證公平阻塞,能夠經過配置建立公平阻塞的隊列,實現原理是可重入鎖。
LinkedBlockingQueue,一個由鏈表結構組成的有界阻塞隊列 fifo,LinkedBlockingQueue 可無界,也能夠有界,初始化指定長度則爲有界,不指定則爲無界
PriorityBlockingQueue,一個支持優先級排序的無界阻塞隊列
synchronousQueue,一個不存儲元素的阻塞隊列
十一、線程狀態有幾種?
答:線程的生命週期爲5個狀態,新建狀態、就緒狀態(start)、運行狀態(run)、阻塞狀態和死亡狀態。
運行的線程執行sleep線程進入阻塞狀態,sleep時間到了之後進入就緒狀態。
線程的實現由3種方法:繼承Tread類;實現Runnable接口;實現Callable接口
Sleep和wait的區別:sleep屬於Thread類,wait屬於Object類,
sleep線程不會釋放對象鎖,wait會釋放對象鎖;
wait須要調用notify()方法後本線程才進入對象索定池(只能同步方法或同步代碼塊中使用),sleep結束後進入就緒狀態。
notify()與notifyAll()的區別:notify()隨機通知一個線程;
notifyAll()通知全部線程;
十一、Java8新特性
答:(1) lambda表達式 (2) Stream,處理集合數據(3) 接口default方法,有利於數據移植
十二、抽象類和接口
答:抽象類和抽象方法都須要被abstract修飾,抽象方法必定要定義在抽象類中。抽象類全部方法都是抽象方法的時候,徹底能夠用接口實現。抽象類爲部分方法提供實現,避免了子類重複實現這些方法,提供了代碼重用性。單繼承,多實現。既要定義子類的行爲,又要爲子類提供共性功能時才選用抽象類。
1三、內部類
靜態內部類:static修飾,能夠訪問外部類全部的靜態變量和方法。應用場景如hashmap的靜態內部類entry
成員內部類:能夠訪問外部類全部的變量和方法。和靜態內部類不一樣,成員內部類的實例都依賴外部類的實例。
局部內部類:即定義在方法中的類,能夠訪問外部類的全部變量和方法,若是局部內部類用static修飾方法內,則只能訪問外部類的static變量
匿名內部類:匿名內部類能夠出如今任何容許表達式出現的地方,定義格式爲new 類/接口。應用場景,分佈式工具類,多線程,android中的綁定監聽事件。
1三、反射
反射是java在運行狀態下,對於任意一個類,都可以知道這個類的全部屬性和方法;
優勢是能夠動態建立對象和編譯;缺點是對性能有影響。
獲取方式有3種:類名.class,Class.forName(xxx); new 類名.getclass()。
反射的應用場景有:反編譯、mybatis底層實現、工具類,bean轉map,經過反射獲取註解,能夠作一些校驗
1四、java面向對象的三大特性
繼承:是對有共同特性的多類事物,進行再抽象成一個類。java繼承是extends關鍵字,子類中有和父類中可訪問的同名同返回同參數列表的方法時,就會覆蓋從父類繼承來的方法
封裝:隱藏對象的屬性和實現細節,僅對外提供接口。java中的類屬性訪問權限不是private,要想隱藏該類方法須要用private修飾符
多態:兩種機制:編譯時多態和運行時多態.
方法重載,方法名相同,其餘不一樣,編譯時重載。方法重寫(覆蓋),子類覆蓋父類的方法。
1五、泛型
泛型只在編譯階段有效,在編譯過程當中,正確檢測泛型結果後,會將泛型的相關信息擦除,而且添加類型檢測和類型轉換。
使用泛型的好處是:類型安全;消除強制類型轉換,提升性能。
泛型的具體使用有3種方式:
(1) 泛型類,例如hashmap<K,V>,其中key和value只在運行時纔會真正根據類型來構造和分配內存
(2) 泛型接口,當2個接口的處理方式一致,只是對象不一樣的時候,能夠用泛型接口
(3) 泛型方法,把方法參數泛型話
1六、join是怎麼實現的?
join是thread類synchronized修飾的同步方法,其使用wait()方法實現等待;
1七、異常
1、error
程序沒法處理的錯誤,比較嚴重的問題,虛擬機錯誤,如OutOfMemoryError、NoClassDefFoundError
2、exception
一、已檢查異常
編譯器要求必須對代碼try catch或者throw expetion,如IOException、SQLException、FileNotFoundException、ParseException
二、未檢查異常(RuntimeException運行時異常)
編譯時不檢查,運行時可能發生的異常,如NullPointerException,IndexOutOfBoundsException
1八、有return的狀況下try catch finally的執行順序:
(1)無論有沒有出現異常,當執行到try內時,finally塊中代碼都會執行;
(2)當try和catch中有return時,finally仍然會執行;
(3)finally是在return後面的表達式運算後執行的(此時並無返回運算後的值,而是先把要返回的值保存起來,無論finally中的代碼怎麼樣,返回的值都不會改變(對象類型須要另外分析),仍然是以前保存的值),因此函數返回值是在finally執行前肯定的;
(4)finally中最好不要包含return,不然程序會提早退出,返回值不是try或catch中保存的返回值。
1九、對象的初始化順序:
(1)類加載以後,按從上到下(從父類到子類)執行被static修飾的語句;
(2)當static語句執行完以後,再執行main方法;
(3)若是有語句new了自身的對象,將從上到下執行構造代碼塊、構造器(二者能夠說綁定在一塊兒)。
20、cookie與session
Web應用程序是使用HTTP協議傳輸數據的。HTTP協議是無狀態的協議。一旦數據交換完畢,客戶端與服務器端的鏈接就會關閉,再次交換數據須要創建新的鏈接。這就意味着服務器沒法從鏈接上跟蹤會話。要跟蹤該會話,必須引入一種機制。
Cookie就是這樣的一種機制。它能夠彌補HTTP協議無狀態的不足。在Session出現以前,基本上全部的網站都採用Cookie來跟蹤會話。
Cookie其實是一小段的文本信息。客戶端請求服務器,若是服務器須要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。
Cookie具備不可跨域名性。
ookie生命週期默認爲瀏覽器會話期間,駐留內存,關閉瀏覽器cookie就沒了
設置cookie的過時時間爲永不過時,將cookie保存在硬盤上
首先瀏覽器請求服務器訪問web站點時,程序須要爲客戶端的請求建立一個session的時候,服務器首先會檢查這個客戶端請求是否已經包含了一個session標識、稱爲SESSIONID,若是已經包含了一個sessionid則說明之前已經爲此客戶端建立過session,服務器就按照sessionid把這個session檢索出來使用,若是客戶端請求不包含session id,則服務器爲此客戶端建立一個session而且生成一個與此session相關聯的session id,sessionid 的值應該是一個既不會重複,又不容易被找到規律以仿造的字符串,這個sessionid將在本次響應中返回到客戶端保存,保存這個sessionid的方式就能夠是cookie,這樣在交互的過程當中,瀏覽器能夠自動的按照規則把這個標識發回給服務器,服務器根據這個sessionid就能夠找獲得對應的session,又回到了這段文字的開始
關閉瀏覽器不會致使session被刪除,迫使服務器爲seesion設置了一個失效時間,通常是30分鍾
當瀏覽器將cookie禁用,基於cookie的session將不能正常工做,每次使用request.getSession() 都將建立一個新的session。達不到session共享數據的目的,可是咱們知道原理,只須要將session id 傳遞給服務器session就能夠正常工做的。
解決:經過URL將session id 傳遞給服務器:URL重寫
2一、通訊方式
1、進程間的通訊方式
# 管道( pipe ):管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程關係。
# 有名管道 (namedpipe) : 有名管道也是半雙工的通訊方式,可是它容許無親緣關係進程間的通訊。
# 信號量(semophore ) : 信號量是一個計數器,能夠用來控制多個進程對共享資源的訪問。它常做爲一種鎖機制,防止某進程正在訪問共享資源時,其餘進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。
# 消息隊列( messagequeue ) : 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
# 信號 (sinal ) : 信號是一種比較複雜的通訊方式,用於通知接收進程某個事件已經發生。
# 共享內存(shared memory ) :共享內存就是映射一段能被其餘進程所訪問的內存,這段共享內存由一個進程建立,但多個進程均可以訪問。共享內存是最快的 IPC 方式,它是針對其餘進程間通訊方式運行效率低而專門設計的。它每每與其餘通訊機制,如信號量,配合使用,來實現進程間的同步和通訊。
# 套接字(socket ) : 套解口也是一種進程間通訊機制,與其餘通訊機制不一樣的是,它可用於不一樣及其間的進程通訊。
2、線程間的通訊方式
# 鎖機制:包括互斥鎖、條件變量、讀寫鎖
*互斥鎖提供了以排他方式防止數據結構被併發修改的方法。
*讀寫鎖容許多個線程同時讀共享數據,而對寫操做是互斥的。
*條件變量能夠以原子的方式阻塞進程,直到某個特定條件爲真爲止。對條件的測試是在互斥鎖的保護下進行的。條件變量始終與互斥鎖一塊兒使用。
# 信號量機制(Semaphore):包括無名線程信號量和命名線程信號量
# 信號機制(Signal):相似進程間的信號處理
線程間的通訊目的主要是用於線程同步,因此線程沒有像進程通訊中的用於數據交換的通訊機制。
2二、使用DateTimeFormatter
若是是Java8應用,可使用DateTimeFormatter代替SimpleDateFormat,這是一個線程安全的格式化工具類。