Java常見面試題

1.集合線程不安全解決

故障現象

public class ContainerDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                list.add(random.nextInt(10));
                System.out.println(list);
            }).start();
        }
    }
}
故障現象java.util.ConcurrentModificationException

導致原因

併發修改導致的異常

解決方案

new Vector();
Collections.synchronizedList(new ArrayList<>());
List list = new CopyOnWriteArrayList<>();

優化建議

讀多寫少的時候推薦使用Java.util. concurrent.CopeOnWriteArrayList 類

2.Java中的鎖synchronized 和 Lock 有什麼區別?

1.原始結構

synchronized 是關鍵字屬於 JVM 層面,反應在字節碼上是 monitorenter 和 monitorexit,其底層是通過 monitor 對象來完成,其實 wait/notify 等方法也是依賴 monitor 對象只有在同步快或方法中才能調用 wait/notify 等方法。
Lock 是具體類(java.util.concurrent.locks.Lock)是 api 層面的鎖。

2.使用方法

synchronized 不需要用戶手動去釋放鎖,當 synchronized 代碼執行完後系統會自動讓線程釋放對鎖的佔用。
ReentrantLock 則需要用戶手動的釋放鎖,若沒有主動釋放鎖,可能導致出現死鎖的現象,lock() 和 unlock() 方法需要配合 try/finally 語句來完成。

3.等待是否可中斷

synchronized 不可中斷,除非拋出異常或者正常運行完成。
ReentrantLock 可中斷,設置超時方法 tryLock(long timeout, TimeUnit unit),lockInterruptibly() 放代碼塊中,調用 interrupt() 方法可中斷.

4.加鎖是否公平

synchronized 非公平鎖
ReentrantLock 默認非公平鎖,構造方法中可以傳入 boolean 值,true 爲公平鎖,false 爲非公平鎖。

5.鎖可以綁定多個 Condition

synchronized 沒有 Condition。
ReentrantLock 用來實現分組喚醒需要喚醒的線程們,可以精確喚醒,而不是像 synchronized 要麼隨機喚醒一個線程要麼喚醒全部線程。

3.死鎖編碼以及定位分析(項目怎麼解決異常,遇到的難題是什麼)

產生死鎖的原因

1.系統資源不足。2.系統資源分配不足
死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種相互等待的現象,如果無外力的干涉那它們都將無法推進下去,如果系統的資源充足,進程的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖。

  • jps -l 命令查定位進程號
    在這裏插入圖片描述
28519 org.jetbrains.jps.cmdline.Launcher
32376 com.intellij.idea.Main
28521 com.cuzz.thread.DeadLockDemo
27836 org.jetbrains.kotlin.daemon.KotlinCompileDaemon
28591 sun.tools.jps.Jps
  • jstack 28521 找到死鎖查看
    在這裏插入圖片描述
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.191-b12 mixed mode):

"Attach Listener" #13 daemon prio=9 os_prio=0 tid=0x00007f7acc001000 nid=0x702a waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
// ...
Found one Java-level deadlock:
=============================
"pool-1-thread-2":
  waiting to lock monitor 0x00007f7ad4006478 (object 0x00000000d71f60b0, a java.lang.String),
  which is held by "pool-1-thread-1"
"pool-1-thread-1":
  waiting to lock monitor 0x00007f7ad4003be8 (object 0x00000000d71f60e8, a java.lang.String),
  which is held by "pool-1-thread-2"

Java stack information for the threads listed above:
===================================================
"pool-1-thread-2":
        at com.cuzz.thread.DeadLockDemo.method(DeadLockDemo.java:34)
        - waiting to lock <0x00000000d71f60b0> (a java.lang.String)
        - locked <0x00000000d71f60e8> (a java.lang.String)
        at com.cuzz.thread.DeadLockDemo.lambda$main$1(DeadLockDemo.java:21)
        at com.cuzz.thread.DeadLockDemo$$Lambda$2/2074407503.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
"pool-1-thread-1":
        at com.cuzz.thread.DeadLockDemo.method(DeadLockDemo.java:34)
        - waiting to lock <0x00000000d71f60e8> (a java.lang.String)
        - locked <0x00000000d71f60b0> (a java.lang.String)
        at com.cuzz.thread.DeadLockDemo.lambda$main$0(DeadLockDemo.java:20)
        at com.cuzz.thread.DeadLockDemo$$Lambda$1/558638686.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

4.線程池難點

爲什使用線程池,線程池的優勢?

線程池用於多線程處理中,它可以根據系統的情況,可以有效控制線程執行的數量,優化運行效果。線程池做的工作主要是控制運行的線程的數量,處理過程中將任務放入隊列,然後在線程創建後啓動這些任務,如果線程數量超過了最大數量,那麼超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。

主要特點爲

1.線程複用。2.控制最大併發數量。3.管理線程

主要優點

1.低資源消耗,通過重複利用已創建的線程來降低線程創建和銷燬造成的消耗。
2.提高相應速度,當任務到達時,任務可以不需要的等到線程創建就能立即執行。
3.提高線程的可管理性,線程是稀缺資源,如果無限制的創建,不僅僅會消耗系統資源,還會降低體統的穩定性,使用線程可以進行統一分配,調優和監控。

線程池使用
在這裏插入圖片描述
ThreadPoolExecutor最重要的底層源碼實現類

ThreadPoolExecutor作爲java.util.concurrent包對外提供基礎實現,以內部線程池的形式對外提供管理任務執行,線程調度,線程池管理等等服務。

有五種常使用三種

ExecutorService thread1 = Executors.newFixedThreadPool(5);//一個池五個線程
thread1.execute(new Runnable());//開啓線程池,沒有返回值。可以執行任務,但無法判斷任務是否成功完成。
Future future = thread1.submit(new Runnable());//開啓線程池,返回一個future。可以用這個future來判斷任務是否成功完成
thread1.shutdown();//關閉線程池

ExecutorService thread2 = Executors.newSigleThreadExecutor();//一個池1個處理線程

ExecutorService thread3 = Executors.newCachedThreadPool();//一個池N個處理線程

在這裏插入圖片描述
7大參數

參數 說明
corePoolsize 線程池中的常駐核心線程數
maximumpoolsiz 線池能夠容納同時執行的最大線程數,此值必須大於等於1
keepalivetime 多餘的空閒線程的存活時間多餘空閒線程會被銷燬直到只剩下 corepoolSize個線程爲止
TimeUnit keepAliveTime 時間單位
workQueue 任務隊列,被提交但尚未被執行的任務
threadFactory 表示生成線程池中工作線程的線程工廠,用於創建線程一般用默認的即可
RejectedExecutionHandler 當提交任務數超過 maxmumPoolSize+workQueue 之和時,任務會交給RejectedExecutionHandler 來處理

在這裏插入圖片描述
在這裏插入圖片描述
原理

1.當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閒線程。
2.當線程池達到corePoolSize時,新提交任務將被放入 workQueue 中,等待線程池中任務調度執行。
3.當workQueue已滿,且 maximumPoolSize 大於 corePoolSize 時,新提交任務會創建新線程執行任務。
4.當提交任務數超過 maximumPoolSize 時,新提交任務由 RejectedExecutionHandler 處理。
5.當線程池中超過corePoolSize 線程,空閒時間達到 keepAliveTime 時,關閉空閒線程 。
6.當設置allowCoreThreadTimeOut(true) 時,線程池中 corePoolSize 線程空閒時間達到 keepAliveTime 也將關閉。

生產環境使用的線程池手寫(不使用JDK裏)
在這裏插入圖片描述

public class ThreadPoolExecutorDemo {
    public static void main(String[] args) {
        Executor executor = new ThreadPoolExecutor(2, 3, 1L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(5), 
                Executors.defaultThreadFactory(), 
                new ThreadPoolExecutor.DiscardPolicy());
    }
}

合理配置線程池考慮二點

1.CPU 密集型
CPU 密集的意思是該任務需要大量的運算,而沒有阻塞,CPU 一直全速運行。
CPU 密集型任務儘可能的少的線程數量,一般爲 CPU 核數 + 1 個線程的線程池。
2.IO 密集型
由於 IO 密集型任務線程並不是一直在執行任務,可以多分配一點線程數,如 CPU * 2 。
也可以使用公式:CPU 核數 / (1 - 阻塞係數);其中阻塞係數在 0.8 ~ 0.9 之間。

5.Linux查性能命令

top 查看機器性能 簡寫uptime
在這裏插入圖片描述
vmstat 主要查看CPU性能
在這裏插入圖片描述
free 看內存
在這裏插入圖片描述
df 看硬盤
在這裏插入圖片描述
ps 查看進程 kill 3163結束進程

find 文件搜索 grep 在文本里面搜索內容

發佈了66 篇原創文章 · 獲贊 68 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章