Java 中的鎖如何使用?有什麼注意事項?

Java 中常見的鎖有 synchronized 可重入鎖 java.util.concurrent.lock.ReentrantLock 可重複讀寫鎖 java.util.concurrent.lock.ReentrantReadWriteLock java

 synchronized 有 3種用法編程

 修飾普通方法,執行方法代碼,須要獲取對象自己 this 的鎖 緩存

 package constxiong.concurrency.a18; import java.util.ArrayList; import java.util.List; /** * 測試 synchronized 普通方法 * @author ConstXiong * @date 2019-09-19 10:49:46 */ public class TestSynchronizedNormalMethod { private int count = 0; // private void add1000() { private synchronized void add1000() { //使用 synchronized 修飾 add100 方法,便可得到正確的值 30000 for (int i = 0; i < 1000; i++) { count++; } } //啓動 30 個線程,每一個線程 對 TestSynchronized 對象的 count 屬性加 1000 private void test() throws InterruptedException { List<Thread> threads = new ArrayList<Thread>(10); for (int i = 0; i < 30; i++) { Thread t = new Thread(() -> { add1000(); }); t.start(); threads.add(t); } //等待全部線程執行完畢 for (Thread t : threads) { t.join(); } //打印 count 的值 System.out.println(count); } public static void main(String[] args) throws InterruptedException { //建立 TestSynchronizedNormalMethod 對象,調用 test 方法 new TestSynchronizedNormalMethod().test(); } }併發

  • 修飾靜態方法,執行方法代碼,須要獲取 class 對象的鎖
 package constxiong.concurrency.a18; import java.util.ArrayList; import java.util.List; /** * 測試 synchronized 靜態方法 * @author ConstXiong * @date 2019-09-19 10:49:46 */ public class TestSynchronizedStaticMethod { private static int count = 0; private static void add1000() { // private synchronized static void add1000() { //使用 synchronized 修飾 add100 方法,便可得到正確的值 30000 for (int i = 0; i < 1000; i++) { count++; } } public static void main(String[] args) throws InterruptedException { //啓動 30 個線程,每一個線程 對 TestSynchronized 對象的 count 屬性加 1000 List<Thread> threads = new ArrayList<Thread>(10); for (int i = 0; i < 30; i++) { Thread t = new Thread(() -> { add1000(); }); t.start(); threads.add(t); } //等待全部線程執行完畢 for (Thread t : threads) { t.join(); } //打印 count 的值 System.out.println(count); } }
  • 鎖定 Java 對象,修飾代碼塊,顯示指定須要獲取的 Java 對象鎖
 package constxiong.concurrency.a18; import java.util.ArrayList; import java.util.List; /** * 測試 synchronized 代碼塊 * @author ConstXiong * @date 2019-09-19 10:49:46 */ public class TestSynchronizedCodeBlock { private int count = 0; //鎖定的對象 private final Object obj = new Object(); private void add1000() { //執行下面的加 1000 的操做,都須要獲取 obj 這個對象的鎖 synchronized (obj) { for (int i = 0; i < 1000; i++) { count++; } } } //啓動 30 個線程,每一個線程 對 TestSynchronized 對象的 count 屬性加 1000 private void test() throws InterruptedException { List<Thread> threads = new ArrayList<Thread>(10); for (int i = 0; i < 30; i++) { Thread t = new Thread(() -> { add1000(); }); t.start(); threads.add(t); } //等待全部線程執行完畢 for (Thread t : threads) { t.join(); } //打印 count 的值 System.out.println(count); } public static void main(String[] args) throws InterruptedException { //建立 TestSynchronizedNormalMethod 對象,調用 test 方法 new TestSynchronizedCodeBlock().test(); } } 

可重入鎖 java.util.concurrent.lock.ReentrantLock 的使用示例

 package constxiong.concurrency.a18; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 測試 ReentrantLock * @author ConstXiong * @date 2019-09-19 11:26:50 */ public class TestReentrantLock { private int count = 0; private final Lock lock = new ReentrantLock(); private void add1000() { lock.lock(); try { for (int i = 0; i < 1000; i++) { count++; } } finally { lock.unlock(); } } //啓動 30 個線程,每一個線程 對 TestSynchronized 對象的 count 屬性加 1000 private void test() throws InterruptedException { List<Thread> threads = new ArrayList<Thread>(10); for (int i = 0; i < 30; i++) { Thread t = new Thread(() -> { add1000(); }); t.start(); threads.add(t); } //等待全部線程執行完畢 for (Thread t : threads) { t.join(); } //打印 count 的值 System.out.println(count); } public static void main(String[] args) throws InterruptedException { //建立 TestReentrantLock 對象,調用 test 方法 new TestReentrantLock().test(); } } dom

可重複讀寫鎖 java.util.concurrent.lock.ReentrantReadWriteLock 的使用示例

 package constxiong.concurrency.a18; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 測試可重入讀寫鎖 ReentrantReadWriteLock * @author ConstXiong * @date 2019-09-19 11:36:19 */ public class TestReentrantReadWriteLock { //存儲 key value 的 map private Map<String, Object> map = new HashMap<String, Object>(); //讀寫鎖 private final ReadWriteLock lock = new ReentrantReadWriteLock(); /** * 根據 key 獲取 value * @param key */ public Object get(String key) { Object value = null; lock.readLock().lock(); try { Thread.sleep(50L); value = map.get(key); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } return value; } /** * 設置key-value * @param key */ public void set(String key, Object value) { lock.writeLock().lock(); try { Thread.sleep(50L); map.put(key, value); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } //測試5個線程讀數據,5個線程寫數據 public static void main(String[] args) { //建立測試可重入讀寫鎖 TestReentrantReadWriteLock 對象 TestReentrantReadWriteLock test = new TestReentrantReadWriteLock(); String key = "lock";//存入 map 中的 key Random r = new Random();//生成隨機數做爲 value for (int i = 0; i < 5; i++) { //5 個線程讀 map 中 key 的 value new Thread(() -> { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " read value=" + test.get(key)); } }).start(); //5 個線程寫 map 中 key 的 value new Thread(() -> { for (int j = 0; j < 10; j++) { int value = r.nextInt(1000); test.set(key, value); System.out.println(Thread.currentThread().getName() + " write value=" + value); } }).start(); } } }jvm

鎖的使用注意事項

synchronized 修飾代碼塊時,最好不要鎖定基本類型的包裝類,如 jvm 會緩存 -128 ~ 127 Integer 對象,每次向以下方式定義 Integer 對象,會得到同一個 Integer,若是不一樣地方鎖定,可能會致使詭異的性能問題或者死鎖
Integer i = 100;  synchronized 修飾代碼塊時,要線程互斥地執行代碼塊,須要確保鎖定的是同一個對象,這點每每在實際編程中會被忽視 synchronized 不支持嘗試獲取鎖、鎖超時和公平鎖 ReentrantLock 必定要記得在 finally{} 語句塊中調用 unlock() 方法釋放鎖,否則可能致使死鎖 ReentrantLock 在併發量很高的狀況,因爲自旋很消耗 CPU 資源 ReentrantReadWriteLock 適合對共享資源寫操做不多,讀操做頻繁的場景;能夠從寫鎖降級到讀鎖,沒法從讀鎖升級到寫鎖
相關文章
相關標籤/搜索