天天看點

java基礎題目總結

有些基礎題目由于工作中用的比較少但卻又是不可少的,這樣回答起來就會反應慢,不确定,不準确,特此開了文章記錄遇到的不确定或者回答比較拗口的問題。

1.servlet是單例的嗎,是安全的嗎,是多線程嗎

servlet是單例的,根據web.xml執行個體化一次後,其他通路通過多線程的方式調用servlet執行個體。 是以,關于多線程通路共享變量的安全性問題已經是老生常談了。這裡隻要知道servlet是單例的,其他問題也就解決了。servlet的實作方式決定了安全性。成員變量是否是靜态的,是否上鎖?關于調用成員變量的方法中是否上鎖?或者是否是使用封裝線上程内的局部變量?

2.什麼是線程安全?常用的HashMap,ArrayList是否安全?

線程安全問題的重點還是共享變量的問題,想了解關于共享變量的變化就要了解jmm(java memory model),簡單的說就是線程有工作區,變量放在記憶體堆中。線程工作必須copy一個副本到工作區去工作,這個操作叫做讀取。線程工作結束後将結果寫入記憶體。當多個線程讀和寫的時候就會有順序性問題。jvm的中讀寫無序性使得變量的實際值不确定,每個線程得到的變量的值在于它讀取的時候,而之後的時間内改變也不影響線程自己知道的值,即可見性問題。jvm中線程的工作區是互相不可見的。正是因為線程讀和寫是分兩步進行的,在這之間會發生的其他操作造成最終結果的不準确,這就是不安全的原因:原子性。隻有保證讀寫操作是原子的才能保證變量的準确性,于是就是線程同步,即上鎖。可以使用synchronized和Lock,還有volatile。 HashMap和ArrayList不是線程安全的。可以使用并發包concurrent下的ConcurrentHashMap,此類采用分段寫鎖提高并發性,保證寫的安全性。同樣CopyOnWriteArrayList通過寫時上鎖并建立副本,在副本寫入後,通過volatile規則使得其他線程可見以及緩存一緻性,使得其他線程中的副本失效。

3.談談對java記憶體模型的了解

java memory model,jmm. 首先,java對變量的操作:讀取,計算,指派都是線上程中實作的,變量是放在主記憶體(即記憶體),而計算的操作必須放線上程的工作區中(對應到硬體就是L1,L2以及寄存器)。線程之間的工作區隻有線程自己持有,其他線程無法通路也看不到。這是jmm對可見性的封裝。線程根據計算的時間不同而無法保證确切的寫入記憶體的時間,即“無序寫入”。java通過上鎖來保證原子操作,即原子性。java允許編譯器和處理器對指令進行重新排序,但是重排序過程不會影響到單線程程式的執行,卻會影響到多線程并發執行的正确性。,java記憶體模型具備一些先天的“有序性”,即不需要通過任何手段就能夠保證的有序性,這個通常也成為happens-before原則。如果兩個操作的執行次序無法從happens-before原則推導出來,那麼她們就不能保證有序性,虛拟機可以随意地對她們進行重新排序。 程式次序規則:一個線程内,按照代碼順序,書寫在前面的操作先行發生于書寫在後面的操作 鎖定規則:一個unlock操作先行發生于後面對同一個鎖lock操作。 volatile變量規則:對一個變量的寫操作先行發生于後面對這個變量的讀操作。 傳遞規則:如果操作a線程發生于操作b,而操作b又先行發生于操作c,則可以得出操作a先行發生于操作c。 線程啟動規則:Thread對象的start()方法先行發生于此線程的每一個操作。 線程中斷規則:對于線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷時間的發生。 線程終結規則:線程中所有的操作都先行發生于線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的傳回值手段檢測到線程已經終止執行 對象終結規則:一個對象的初始化完成先行發生于他的finalize()方法的開始 這8條原則摘自《深入了解java虛拟機》。前4條規則是比較重要,後4條顯而易見。

 4.volatile有什麼用?能否用一句話說明下volatile的應用場景?

volatile能保證可見性和一定的有序性。由于線程隻在自己的工作區工作,如果另一個線程修改了變量的值,其他線程如果需要再次讀取變量的值的時候必須從主存中讀取。也就是說無法改變已經讀取了的線程,但保證了可見性和相對的有序性。另外,jvm的規則:volatile變量規則:對一個變量的寫操作先行發生于後面對這個變量的讀操作。這個可以保證語句的先後執行順序。代碼中volatile标記的操作之前的代碼必須執行完畢後才可執行。 應用場景:狀态标記量,用作線程run的條件,如果不用volatile則可能會不讀取記憶體标記,或者不知道何時讀取。代碼順序保證,volatile标記的變量的操作之前的代碼必須執行完畢。double check,雙重檢查。

唯有不斷學習方能改變!

-- <b>Ryan Miao</b>