我們面試中經常會被問到多線程相關知識,這一塊內容往淺了說大家都會,但是一問到底層實現原理,我們往往就一臉懵逼。 這段時間準備好好學習多線程,接下來會寫一系列關於多線程的知識。 我們首先要瞭解線程,百度百科這麼介紹:線程(thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中 ...
我們面試中經常會被問到多線程相關知識,這一塊內容往淺了說大家都會,但是一問到底層實現原理,我們往往就一臉懵逼。
這段時間準備好好學習多線程,接下來會寫一系列關於多線程的知識。
我們首先要瞭解線程,百度百科這麼介紹:線程(thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。
這句話很好理解。一般我們不創建 thread 類的話,程式都是單線程在執行。
線程是有多種狀態的,Thread 類里有個枚舉變數 State 列舉了線程的幾種狀態
下麵這張圖說明瞭線程狀態之間的關係。
程式里有多個線程時,會出現多個線程對同一個對象操作的情況,為了保證同一時間只能有一個線程操作該對象,就引入了鎖機制。
鎖有分散式鎖,java鎖 ,java 鎖有 synchronized 關鍵字,Lock 鎖。今天我們主要講 java 中的 Lock 鎖。
常用的可重入鎖(ReentrantLock)就是實現了 Lock 介面,這次我們就嘗試自己製作一把鎖,當然我們要實現 Lock 介面。
首先來分析如何實現它?
1.需要一個線程的等待集合,所以我們要定義一個list,考慮到先進先出機制,我們用 LinkedBlockingQueue 來存放線程集合
2.需要一個鎖標記,來記錄當前持有鎖的進程,考慮到它的原子性,我們用 AtomicReference 類來存放
3.線程執行完,會釋放鎖,此時要通知其他線程爭搶鎖,這裡又涉及到線程通信。
下圖也是我的分析過程,我們接下來就用代碼來實現。
實現之前,我們先瞭解一些線程通信的知識,我們最常用的方法是 wait/notify,但是 wait/notify 有一個很明顯的缺點,正常順序是 先 wait,再 notify,如果程式先 notify,再 wait,就會進入死鎖狀態,所以它是有順序限制的,但是 park/unpark 方法就不會有這些問題,所以我們用 park/unpark 實現線程通信。
下麵是實現代碼,註釋里寫的很清楚了。
public class MyLock implements Lock { //判斷是否有人拿到鎖 AtomicReference<Thread> owner = new AtomicReference<>(); //等待線程隊列 LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(); @Override public boolean tryLock() { //如果 owner 為空,就把當前線程賦給 owner return owner.compareAndSet(null,Thread.currentThread()); } @Override public void lock() { boolean park = false; while(!tryLock()){ if(!park){ //加入等待集合 waiters.offer(Thread.currentThread()); park = true; }else{ LockSupport.park(); } } waiters.remove(Thread.currentThread()); } @Override public void unlock() { //釋放鎖,要通知等待者 if(owner.compareAndSet(Thread.currentThread(),null)){ //遍歷等待者 ,通知繼續執行 Thread next = null; while ((next = waiters.peek() )!= null){ LockSupport.unpark(next); } } } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public Condition newCondition() { return null; } }
Lock 介面里,還有一些方法沒有實現,當然這都不重要,主要是為了實現 lock 和 unlock 方法。
研究多線程,要多看看 java.util.concurrent 包,把這個包研究透了,多線程也就學的差不多了。畢竟面試中多線程用的還是挺多的。