Java synchronized關鍵字和Lock介面實現原理
這篇文章主要介紹了Java synchronized關鍵字和Lock介面實現原理,文中通過示例程式碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
引用
當開發過程中,我們遇到併發問題。怎麼解決?
一種解決方式,簡單粗暴:上鎖。將千軍萬馬都給攔下來,只允許一個人過獨木橋。書面意思就是將並行的程式變成序列的程式。現實的鎖有門鎖、掛鎖和抽屜鎖等等。在Java中,我們的鎖就是synchronized關鍵字和Lock介面。
synchronized關鍵字
synchronized也叫同步鎖,是Java裡面的關鍵字。我們可以猜測到synchronized原理也JVM虛擬機器有關聯。
synchronized鎖的是物件。物件裡面有一個叫做監視鎖(monitor)的東西,監視鎖依賴作業系統的互斥鎖(Mutex Lock)。作業系統切換執行緒其實就是從使用者態程式設計核心態(cpu的兩種狀態)。這個代價有點高,所以synchronized這個重量級鎖後面也引進了偏向鎖和輕量級鎖。
加鎖(監視鎖monitor)過程分析():
- 當monitor的進入數為0,執行緒A進入
- monitor的進入數為1
- 執行緒B想進入該monitor就會被阻塞。
執行緒A可以重複進入該monitor,所以synchronized是可重入鎖,和Lock實現的鎖一樣。
程式驗證
public class SynchronizedTest { private static int i = 0; public static void main(String[] args) { test(); } public static void test(){ synchronized (SynchronizedTest.class){ synchronized (SynchronizedTest.class){ i++; } } } }
執行結果
程式正常執行,沒有報錯
synchronized可以修飾方法以及程式碼塊,程式碼塊就是上面重入鎖的例子。
修飾方法
public class SynchronizedTest { static int n = 100; final static CountDownLatch start = new CountDownLatch(n); private static int i = 0; public static void main(String[] args) throws InterruptedException { for (int j = 0; j < n; j++) { Thread thread = new Thread(new addNoSynchronized()); thread.start(); } start.await(); System.out.println(i); } public static class addSynchronized implements Runnable{ @Override public void run() { addSynchronized(); } public static synchronized void addSynchronized(){ for (int j = 0; j < 1000; j++) { i++; } start.countDown(); } } }
執行結果
100000
如果去掉 synchronized 關鍵字的話,執行結果大概率不是 100000,因為執行緒不安全問題。
Lock介面
一般我們使用 ReentrantLock 類作為重入鎖,實現Lock介面。
使用方法
public class ReentranLockTest { private static int j; private static int n = 100; private static CountDownLatch latch = new CountDownLatch(n); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < n; i++) { new Thread(new LockTest()).start(); } latch.await(); System.out.println("結果為:"+j); } public static class LockTest implements Runnable{ static Lock lock = new ReentrantLock(); @Override public void run() { lockTest(); latch.countDown(); } private void lockTest() { lock.lock(); try { for (int i = 0; i < 1000; i++) { j++; } }finally { lock.unlock(); } } } }
執行結果
結果為:100000
這裡我們鎖住的 j++ 這塊資源區(公共資源),lock 是 static 關鍵字修飾的,是類物件,思考一下如果不是類物件會怎麼樣?那就是連環鎖了(看圖)。
每一個執行緒都對可以用鑰匙解開這把鎖,對於程式而言,加鎖操作就沒有意義了。因為我們需要的是一個鎖。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。