互聯網Java面試-Java篇

1、HashMap是有序的嗎?

無序

2、有沒有有順序的一個map實現類?

TreeMap、LinkedHashMap

3、TreeMap、LinkedHashMap是如何保證他的順序的?

TreeMap是基於比較器Comparator來實現有序的(TreeMap默認是key升序)。

LinkedHashmap是基於鏈表來實現數據插入有序的(LinkedHashmap默認是數據插入順序)。

4、HashMap是線程安全的嗎?併發下使用的是什麼Map?

不是線程安全的,

使用併發包下的java.util.concurrent.ConcurrentHashMap,ConcurrentHashMap實現了更高級的線程安全;
使用Hashtable 類,Hashtable 是線程安全的;
使用synchronizedMap() 同步方法包裝 HashMap object,得到線程安全的Map,並在此Map上進行操作。

5、CurrentHashMap的實現原理?

JDK 1.8以前,多個數組,分段加鎖,一個數組一個鎖

JDK 1.8之後,優化細粒度,一個數組,每個元素進行CAS,如果失敗說明有人了,此時synchronized對數組元素加鎖,鏈表+紅黑樹,對數組的每個元素加鎖。

6、hashmap的hash算法和尋址算法

在java 1.8 後,
hash算法:高低16位進行異或,讓低16位裏面同時融合了高低16位的一個特徵,避免hash衝突
尋址算法:hash&(n-1),這麼做等同於hash對n取模

7、HashMap如何解決hash碰撞的問題?

鏈表+紅黑樹 O(n)+O(logn)

8、HashMap是如何進行擴容的?默認容量?

2倍擴容 數組長度=16

9、sunchronized關鍵字的底層原理是什麼?

在底層編譯後的jvm指令中,會有monitorenter和monitorexit兩隻指令。monitor的鎖是支持重入加鎖的
在這裏插入圖片描述
10、concurrent下的類都有哪些?

1.Callable:Callable與Runnable類似,Callable有返回。

2.Semaphore:信號量,類似操作系統的P\V操作

3.ReentrantLock與Condition:
1)ReentrantLock是可重入互斥鎖
2)Condition:此類是同步的條件對象,每個Condition實例綁定到一個ReetrantLock中,以便爭用同一個鎖的多線程之間可以通過Condition的狀態來獲取通知。

4.BlockingQueue
BlockingQueue是一個接口,此接口的實現類有:ArrayBlockingQueue, LinkedBlockingDeque。

1)ArrayBlockingQueue
基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,這是一個常用的阻塞隊列,除了一個定長數組外,ArrayBlockingQueue內部還保存着兩個整形變量,分別標識着隊列的頭部和尾部在數組中的位置。生產者和消費者用同一把鎖。

2)LinkedBlockingQueue
基於鏈表的阻塞隊列,同ArrayListBlockingQueue類似,其內部也維持着一個數據緩衝隊列(該隊列由一個鏈表構成),當生產者往隊列中放入一個數據時,隊列會從生產者手中獲取數據,並緩存在隊列內部,而生產者立即返回;只有當隊列緩衝區達到最大值緩存容量時(LinkedBlockingQueue可以通過構造函數指定該值),纔會阻塞生產者隊列,直到消費者從隊列中消費掉一份數據,生產者線程會被喚醒,反之對於消費者這端的處理也基於同樣的原理。而LinkedBlockingQueue之所以能夠高效的處理併發數據,還因爲其對於生產者端和消費者端分別採用了獨立的鎖來控制數據同步,這也意味着在高併發的情況下生產者和消費者可以並行地操作隊列中的數據,以此來提高整個隊列的併發性能。

5.CountDownLatch:初始化一個值N,每個線程調用一次countDown(),那麼cdLatch減1,等所有線程都調用過countDown(),那麼cdLatch值達到0,那麼線程從await()處接着玩下執行。

6.CyclicBarrier:初始化一個值N(相當於一組線程有N個),每個線程調用一次await(),那麼barrier加1,等所有線程都調用過await(),那麼barrier值達到初始值N,所有線程接着往下執行,並將barrier值重置爲0,再次循環下一個屏障;

11、ReentrantLock中AQS原理是什麼?
在這裏插入圖片描述

12、ReentrantLock中的Condition是什麼?

Condition在Lock體系設計中,用於實現與synchronized中monitor對象所提供的wait,notify,notifyAll相同的語義,對應的方法分別爲await,signal,signalAll。在此基礎上進行的優化是:一個Lock可以對應多個Condition,每個Condition對應一個條件化線程等待隊列,而在synchronized中只能使用monitor這一個Condition。

一個Lock支持多個Condition的好處是:可以將等待線程進行分類,即每個Condition對應一個條件化線程等待隊列,而不是全部放在一個條件化線程等待隊列,這樣每個Condition在條件滿足時,可以調用signal或者signalAll來通知該Condition對應的條件化線程等待隊列的線程,而不是所有線程。

13、cyclicbarrier的實現原理?

CyclicBarrier是由ReentrantLock可重入鎖和Condition共同實現的。

14、談談你對Java內存模型的理解
在這裏插入圖片描述
15:、jvm回收算法

年輕代: parnew(複製算法)
老年代:CMS標記清理整理

16、類加載

JVM將class文件字節碼文件加載到內存中, 並將這些靜態數據轉換成方法區中的運行時數據結構,在堆中生成一個代表這個類的java.lang.Class 對象,作爲方法區類數據的訪問入口。

17、外部排序算法

置換選擇排序算法+最佳歸併樹(哈弗曼樹)+敗者樹

18、大量用戶在在內存中排序和去重

一種簡單解決方案就是分而治之,先打大文件分詞大小均勻的若干個小文件,然後對小文件排好序,最後再Merge所有的小文件,在Merge的過程中去掉重複的內容。

19、TCP/IP協議

三次握手:讓雙方都知道自己可以收可以發
四次分手:握手成功後是在自己這裏爲對方準備了一塊資源,現在你要刪除這塊資源,你得問問對方讓不讓你刪除。雙方刪除都得詢問,所以一個四次。

20、網絡分層

應用層:http協議、ftp協議
傳輸層:TCP協議、UDP協議
網絡層:IP協議
數據鏈路層:以太網協議
物理層

21、 java 中守護線程和本地線程區別?

通過方法 Thread.setDaemon(boolean);true 則把該線程設置爲守護線程,反之則爲用戶線程。
如果用戶線程已經全部退出運行了,只剩下守護線程存在了,也就沒有繼續運行程序的必要了。

22、死鎖、活鎖與飢餓的區別?

死鎖:是指兩個或兩個以上的線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。

活鎖:任務或者執行者沒有被阻塞,由於某些條件沒有滿足,導致一直重複嘗試,失敗,嘗試,失敗。

飢餓:一個或者多個線程因爲種種原因無法獲得所需要的資源,導致一直無法執行的狀態

23、Java 中用到的線程調度算法是什麼?

採用時間片輪轉的方式。可以設置線程的優先級,會映射到下層的系統上面的優先級上,如非特別需要,儘量不要用,防止線程飢餓。

24、爲什麼使用 Executor 框架?

每次執行任務創建線程 new Thread()比較消耗性能,創建一個線程是比較耗時、耗資源的。

調用 new Thread()創建的線程缺乏管理,被稱爲野線程,而且可以無限制的創建,線程之間的相互競爭會導致過多佔用系統資源而導致系統癱瘓,還有線程之間的頻繁交替也會消耗很多系統資源。

接使用 new Thread() 啓動的線程不利於擴展,比如定時執行、定期執行、定時定期執行、線程中斷等都不便實現。

25、解決 ABA 問題的原子類

AtomicMarkableReference(通過引入一個 boolean來反映中間有沒有變過)AtomicStampedReference(通過引入一個 int 來累加來反映中間有沒有變過)

26、Lock 和 synchronized的區別

整體上來說 Lock 是 synchronized 的擴展版,Lock 提供了無條件的、可輪詢的(tryLock 方法)、定時的(tryLock 帶參方法)、可中斷的(lockInterruptibly)、可多條件隊列的(newCondition 方法)鎖操作。另外 Lock 的實現類基本都支持非公平鎖(默認)和公平鎖,synchronized 只支持非公平鎖,當然,在大部分情況下,非公平鎖是高效的選擇。

27、什麼是 Callable 和 Future?

Callable 接口類似於 Runnable,從名字就可以看出來了,但是 Runnable 不會返回結果,並且無法拋出返回結果的異常,而 Callable 功能更強大一些,被線程執行後,可以返回值,這個返回值可以被 Future 拿到。也就是說,Future 可以拿到異步執行任務的返回值,Callable可以認爲是帶有回調的 Runnable。

28、什麼是同步容器,什麼是併發容器?

同步容器:可以簡單地理解爲通過 synchronized 來實現同步的容器,如果有多個線程調用同步容器的方法,它們將會串行執行。比如 Vector,Hashtable,以及 Collections.synchronizedSet,synchronizedList 等方法返回的容器。這些容器實現線程安全的方式就是將它們的狀態封裝起來,並在需要同步的方法上加上關鍵字 synchronized。

併發容器:使用了與同步容器完全不同的加鎖策略來提供更高的併發性和伸縮性,例如在 ConcurrentHashMap 中採用了一種粒度更細的加鎖機制,可以稱爲分段鎖,在這種鎖機制下,允許任意數量的讀線程併發地訪問 map,並且執行讀操作的線程和寫操作的線程也可以併發的訪問 map,同時允許一定數量的寫操作線程併發地修改 map,所以它可以在併發環境下實現更高的吞吐量。

29、線程的幾種狀態?

新建狀態(New) 用 new 語句創建的線程處於新建狀態,此時它和其他 Java 對象一樣,僅僅在堆區中被分配了內存。

就緒狀態(Runnable)
當一個線程對象創建後,其他線程調用它的 start()方法,該線程就進入就緒狀態,Java 虛擬機會爲它創建方法調用棧和程序計數器。處於這個狀態的線程位於可運行池中,等待獲得 CPU 的使用權。

運行狀態(Running)
處於這個狀態的線程佔用 CPU,執行程序代碼。只有處於就緒狀態的線程纔有機會轉到運行狀態。

阻塞狀態(Blocked)
阻塞狀態是指線程因爲某些原因放棄 CPU,暫時停止運行。當線程處於阻塞狀態時,Java 虛擬機不會給線程分配 CPU。直到線程重新進入就緒狀態,它纔有機會轉到運行狀態。

死亡狀態(Dead)
當線程退出 run()方法時,就進入死亡狀態,該線程結束生命週期。

30、你將如何分析 Thread dump?

/* 時間,jvm 信息 */
2017-11-01 17:36:28
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):
/* 線程名稱:DestroyJavaVM
編號:#13
優先級:5
系統優先級:0
jvm 內部線程 id:0x0000000001c88800
對應系統線程 id(NativeThread ID):0x1c18
線程狀態: waiting on condition [0x0000000000000000] (等待某個條件)
線程詳細狀態:java.lang.Thread.State: RUNNABLE 及之後所有*/
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000001c88800 nid=0x1c18 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE 

"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000018d49000 nid=0x17b8 waiting for monitor entry [0x0000000019d7f000]
/* 線程狀態:阻塞(在對象同步上)
代碼位置:at com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56) 
等待鎖:0x00000000d629b4d8
已經獲得鎖:0x00000000d629b4e8*/
java.lang.Thread.State: BLOCKED (on object monitor) at com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)
- waiting to lock <0x00000000d629b4d8> (a java.lang.Object)
- locked <0x00000000d629b4e8> (a java.lang.Object)

31、Java 中你怎樣喚醒一個阻塞的線程?

解決方案可以使用以對象爲目標的阻塞,即利用 Object 類的 wait()和 notify()方
法實現線程阻塞。

首先,wait、notify 方法是針對對象的,調用任意對象的 wait()方法都將導致線程阻塞,阻塞的同時也將釋放該對象的鎖,相應地,調用任意對象的 notify()方法則將隨機解除該對象阻塞的線程,但它需要重新獲取改對象的鎖,直到獲取成功才能往下執行;

wait、notify 方法必須在 synchronized 塊或方法中被調用,並且要保證同步塊或方法的鎖對象與調用 wait、notify 方法的對象是同一個,如此一來在調用 wait 之前當前線程就已經成功獲取某對象的鎖,執行 wait 阻塞後當前線程就將之前獲取的對象鎖釋放。

32、Java 中用到的線程調度算法是什麼?

有兩種調度算法:時間片輪轉算法和搶佔式調度算法。

時間片輪轉算法:指讓所有的線程輪流獲得 cpu 的使用權,並且平均分配每個線程佔用的 CPU 的時間片這個也比較好理解。

搶佔式調度算法:指優先讓可運行池中優先級高的線程佔用CPU,如果可運行池中的線程優先級相同,那麼就隨機選擇一個線程,使其佔用CPU。處於運行狀態的線程會一直運行,直至它不得不放棄 CPU。

33、如何停止一個正在運行的線程?

使用共享變量的方式:該變量可以被多個執行相同任務的線程用來作爲是否中斷的信號,通知中斷線程的執行。

如果一個線程由於等待某些事件的發生而被阻塞,比如當一個線程由於需要等候鍵盤輸入而被阻塞,或者調用Thread.join()方法,或者 Thread.sleep()方法,在網絡中調用
ServerSocket.accept()方法,那麼又該怎樣停止該線程呢?

使用 interrupt 方法終止線程:它可以使一個被阻塞的線程拋出一箇中斷異常,從而使線程提前結束阻塞狀態,退出堵塞代碼。

34、什麼是可重入鎖(ReentrantLock)?

先說什麼是不可重入鎖:

public class UnReentrant{
	Lock lock = new Lock();
	public void outer(){
		lock.lock();
		inner();
		lock.unlock();
	}
	public void inner(){
		lock.lock();
		//do something
		lock.unlock();
	} 
}

不可重入鎖:outer 中調用了 inner,outer 先鎖住了 lock,這樣 inner 就不能再獲取lock。其實調用 outer 的線程已經獲取了 lock 鎖,但是不能在 inner 中重複利用已經獲取的鎖資源。

synchronized、ReentrantLock 都是可重入的鎖,可重入鎖相對來說簡化了併發編程的開發。

35、CopyOnWriteArrayList 可以用於什麼應用場景?

CopyOnWriteArrayList(免鎖容器)的好處之一是當多個迭代器同時遍歷和修改這個列表時,不會拋出 ConcurrentModificationException。在CopyOnWriteArrayList 中,寫入將導致創建整個底層數組的副本,而源數組將保留在原地,使得複製的數組在被修改時,讀取操作可以安全地執行。

1、由於寫操作的時候,需要拷貝數組,會消耗內存,如果原數組的內容比較多的情況下,可能導致 young gc 或者 full gc;
2、不能用於實時讀的場景,像拷貝數組、新增元素都需要時間,所以調用一個 set操作後,讀取到數據可能還是舊的,雖然 CopyOnWriteArrayList 能做到最終一致性,但是還是沒法滿足實時性要求;

CopyOnWriteArrayList 透露的思想
1、讀寫分離,讀和寫分開
2、最終一致性
3、使用另外開闢空間的思路,來解決併發衝突

36、volatile 有什麼用?

volatile 保證內存可見性和禁止指令重排。

37、在 java 中 wait 和 sleep 方法的不同?

wait()方法會釋放 CPU 執行權 和 佔有的鎖

sleep(long)方法僅釋放 CPU 使用權,鎖仍然佔用

yield()方法僅釋放 CPU 執行權,鎖仍然佔用

38、爲什麼 wait, notify 和 notifyAll 這些方法不在 thread類裏面?

一個很明顯的原因是 JAVA 提供的鎖是對象級的而不是線程級的,每個對象都有鎖,通過線程獲得。

39、什麼是 ThreadLocal 變量?

每個線程提供一個自己獨有的變量拷貝,將大大提高效率。在沒有使用高代價的同步的情況下獲得了線程安全。

40、怎麼檢測一個線程是否擁有鎖?

在 java.lang.Thread 中有一個方法叫 holdsLock(),它返回 true。

41、你如何在 Java 中獲取線程堆棧?

kill -3 [java pid]:不會在當前終端輸出,它會輸出到代碼執行的或指定的地方去。
Jstack [java pid]:在當前終端顯示,也可以重定向到指定文件中。

42、Thread 類中的 yield 方法有什麼作用?

使當前線程從執行狀態(運行狀態)變爲可執行態(就緒狀態)。當前線程到了就緒狀態,那麼接下來哪個線程會從就緒狀態變成執行狀態呢?可能是當前線程,也可能是其他線程,看系統的分配了。

43、volatile 變量和 atomic 變量有什麼不同?

Volatile 變量可以確保先行關係,即寫操作會發生在後續的讀操作之前, 但它並不
能保證原子性。

AtomicInteger 類提供的 atomic 方法可以讓這種操作具有原子性如getAndIncrement()方法會原子性的進行增量操作把當前值加一。

44、併發編程三要素?

1、原子性
原子性指的是一個或者多個操作,要麼全部執行並且在執行的過程中不被其他操作打斷,要麼就全部都不執行。
2、可見性
可見性指多個線程操作一個共享變量時,其中一個線程對變量進行修改後,其他線程可以立即看到修改的結果。
3、有序性
有序性,即程序的執行順序按照代碼的先後順序來執行。

45、線程池原理
在這裏插入圖片描述
46、線程池的5種狀態

1、RUNNING:能夠接收新任務,以及對已添加的任務進行處理。

2、 SHUTDOWN:不接收新任務,但能處理已添加的任務。

3、STOP:線程池處在STOP狀態時,不接收新任務,不處理已添加的任務,並且會中斷正在處理的任務。

4、TIDYING:當所有的任務已終止

5、 TERMINATED:線程池徹底終止,就變成TERMINATED狀態。

47、CAS的實現原理(compare and set)
在這裏插入圖片描述

48、CAS 的問題

1、CAS 容易造成 ABA 問題
一個線程 a 將數值改成了 b,接着又改成了 a,此時 CAS 認爲是沒有變化,其實是已經變化過了,而這個問題的解決方案可以使用版本號標識,每操作一次version 加 1。在 java5 中,已經提供了 AtomicStampedReference 來解決問題。

2、不能保證代碼塊的原子性
CAS 機制所保證的知識一個變量的原子性操作,而不能保證整個代碼塊的原子性。比如需要保證 3 個變量共同進行原子性的更新,就不得不使用 synchronized 了。

3、CAS 造成 CPU 利用率增加
之前說過了 CAS 裏面是一個循環判斷的過程,如果線程一直沒有獲取到狀態,cpu資源會一直被佔用。

49、AQS的實現原理?

ReentrantLock:state變量、CAS、失敗後進入隊列等待、釋放鎖後喚醒
默認:非公平鎖
在這裏插入圖片描述
50、short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?

答:對於 short s1 = 1; s1 = s1 + 1;由於 1 是 int 類型,因此 s1+1 運算結果也是 int型,需要強制轉換類型才能賦值給 short 型。
而 short s1 = 1; s1 += 1;可以正確編譯,因爲 s1+= 1;相當於 s1 = (short)(s1 + 1);其中有隱含的強制類型轉換。

51、解釋內存中的棧(stack)、堆(heap)和方法區(method area)的用法。

棧:通常我們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用 JVM 中的棧空間;
堆:而通過 new 關鍵字和構造器創建的對象則放在堆空間,堆是垃圾收集器管理的主要區域,
方法區(元空間):用於存儲已經被 JVM 加載的類信息、常量、靜態變量、JIT 編譯器編譯後的代碼等數據;程序中的字面量(literal)如直接書寫的 100、”hello”和常量都是放在常量池中,常量池是方法區的一部分。

52、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?

Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四捨五入的原理是在參數上加 0.5 然後進行下取整

53、構造器(constructor)是否可被重寫(override)?

構造器不能被繼承,因此不能被重寫,但可以被重載。

54、StringBuilder、StringBuffer 的區別?

StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在於它是在單線程環境下使用的,因爲它的所有方面都沒有被synchronized 修飾。

55、抽象類(abstract class)和接口(interface)有什麼異同?

接口比抽象類更加抽象,因爲抽象類中可以定義構造器,可以有抽象方法和具體方法,而接口中不能定義構造器而且其中的方法全部都是抽象方法。

抽象類中的成員可以是 private、默認、protected、public 的,而接口中的成員全都是 public 的。

56、Java 中會存在內存泄漏嗎,請簡單描述。

會導致內存泄露的發生。例如Hibernate 的 Session(一級緩存)中的對象屬於持久態,垃圾回收器是不會回收這些對象的,如果不及時關閉(close)或清空(flush)一級緩存就可能導致內存泄露。

57、抽象的(abstract)方法是否可同時是靜態的(static)

抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。

58、如何實現對象克隆?

有兩種方式:
1). 實現 Cloneable 接口並重寫 Object 類中的 clone()方法;
2). 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆

59、String s = new String(“xyz”);創建了幾個字符串對象?

兩個對象,一個是靜態區的”xyz”,一個是用 new 創建在堆上的對象。

60、如何實現字符串的反轉及替換?

public static String reverse(String originStr) {
	if(originStr == null || originStr.length() <= 1)
		return originStr;
	return reverse(originStr.substring(1)) + originStr.charAt(0);
}

61、日期和時間

Java 8 中引入了新的時間日期 API,其中包括 LocalDate、LocalTime、LocalDateTime、
Clock、Instant 等類,這些的類的設計都使用了不變模式,因此是線程安全的設計。

62、try{}裏有一個 return 語句,那麼緊跟在這個 try 後的finally{}裏的代碼會不會被執行,什麼時候被執行,在 return前還是後?

會執行,在方法返回調用者前執行。

63、TreeMap 和 TreeSet 在排序時如何比較元素?Collections 工具類中的 sort()方法如何比較元素?

TreeSet 要求存放的對象所屬的類必須實現 Comparable 接口,該接口提供了比較元素的 compareTo()方法,當插入元素時會回調該方法比較元素的大小。

Collections 工具類的 sort 方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對象比較實現 Comparable 接口以實現元素的比較;第二種不強制性的要求容器中的元素必須可比較,但是要求傳入第二個參數,參數是Comparator 接口的子類型(需要重寫 compare 方法實現元素的比較),相當於一個臨時定義的排序規則,其實就是通過接口注入比較元素大小的算法,也是對回調模式的應用(Java 中對函數式編程的支持)。

64、闡述 JDBC 操作數據庫的步驟。

//加載驅動。
Class.forName("oracle.jdbc.driver.OracleDriver");
//創建連接。
Connection con =DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott", "tiger");
//創建語句。
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?");
ps.setInt(1, 1000);
ps.setInt(2, 3000);
//執行語句。
ResultSet rs = ps.executeQuery();
while(rs.next()) {
	System.out.println(rs.getInt("empno") + " - " +
	rs.getString("ename"));
} 
//關閉資源。
finally {
	if(con != null) {
	try {
		con.close();
	} catch (SQLException e) {
	e.printStackTrace();
} } }

65、數據庫事務的 ACID 是指什麼?

原子性(Atomic):事務中各項操作,要麼全做要麼全不做,任何一項操作的失敗都會導致整個事務的失敗;
一致性(Consistent):事務結束後系統狀態是一致的;
隔離性(Isolated):併發執行的事務彼此無法看到對方的中間狀態;
持久性(Durable):事務完成後所做的改動都會被持久化,即使發生災難性的失敗。通過日誌和同步備份可以在故障發生後重建數據。

66、用 Java 寫一個單例類。

//餓漢式單例
public class Singleton {
	private Singleton(){}
	private static Singleton instance = new Singleton();
	public static Singleton getInstance(){
		return instance;
	} 
}
//懶漢式單例
public class Singleton {
	private static Singleton instance = null;
	private Singleton() {}
	public static Singleton getInstance(){
		if (instance == null) {
			synchronized(Singleton.class)
			if (instance == null) {
				instance = new Singleton();
			}
		}
		return instance;
}

67、volatile 修飾符的有過什麼實踐?

一種實踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫。double 和 long 都是 64 位寬,因此對這兩種類型的讀是分爲兩部分的,第一次讀取第一個 32 位,然後再讀剩下的 32 位,這個過程不是原子的,但 Java 中volatile 型的 long 或 double 變量的讀寫是原子的。

68、Java 中的 TreeMap 是採用什麼樹實現的?

Java 中的 TreeMap 是使用紅黑樹實現的

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