天天看點

Lock 鎖

原理

基于将多線程并行任務通過某一種機制實作線程的串行執行,進而達到線程安全性的目的。

簡介

在 Lock 之前,隻能基于 synchronized 關鍵字來解決并發安全問題。但是 synchronized 不适合于所有的并發場景。Lock 可以解決而且更加靈活

ReentrantLock

表示重入鎖(互斥鎖),它是唯一一個實作了 Lock 接口的類。重入鎖指的是線程在獲得鎖之後,再次擷取該鎖不需要阻塞,而是直接關聯一次計數器增加重入次數,目的是避免線程的死鎖。大部分情況下可以使用 synchronized,性能上并無太大差别,使用ReentrantLock要特别注意在finally中釋放鎖,不然容易出現死鎖。

特性

  1. 可指定公平和非公平鎖
  2. 提供Condition類,可分組喚醒需要喚醒的線程
  3. 提供能夠中斷等待鎖的線程
  4. 自旋,避免鎖進入核心态

code

public class ReentrantLockDemo {
    // 請求總數
    public static int clientTotal = 5000;
    // 同時并發執行的線程數
    public static int threadTotal = 200;
    public static int count = 0;
    private final static Lock lock = new ReentrantLock();

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        lock.lock();
        try {
            count++;
        } finally {
            // 一定要記得在finally中釋放鎖
            lock.unlock();
        }
    }
}      

ReentrantReadWriteLock

code

public class LockExample3 {
    private final Map<String, Data> map = new TreeMap<>();
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();

    public Data get(String key) {
        // 讀取資料用讀鎖
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public Set<String> getAllKeys() {
         // 讀取資料用讀鎖
        readLock.lock();
        try {
            return map.keySet();
        } finally {
            readLock.unlock();
        }
    }

    public Data put(String key, Data value) {
        // 寫入資料用寫鎖
        writeLock.lock();
        try {
            return map.put(key, value);
        } finally {
            readLock.unlock();
        }
    }

    class Data {
    }
}      

StampedLock

code

public class StampedLockDemo {
    // 請求總數
    public static int clientTotal = 5000;
    // 同時并發執行的線程數
    public static int threadTotal = 200;
    public static int count = 0;
    private final static StampedLock lock = new StampedLock();
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        long stamp = lock.writeLock();
        try {
            count++;
        } finally {
            lock.unlock(stamp);
        }
    }
}