線程鎖

鎖是在多線程中對公共資源的控制。(java.util.concurrent.locks
locks包下的接口:

|---AbstractOwnableSynchronizer
|---AbstractQueuedLongSynchronizer
|---AbstractQueuedSynchronizer
|---Condition
|---Lock
|---LockSupport
|---ReadWriteLock
|---ReentrantLock
|---ReentrantReadWriteLock

樂觀鎖和悲觀鎖

樂觀鎖: 樂觀鎖會認爲每次查詢都不會造成更新丟失,所以每次都不會加鎖,利用版本控制實現。
悲觀鎖: 該鎖認爲每次操作都會對數據造成更新丟失,每次查詢時加上排它鎖。

鎖的類型

  • 可重入鎖
    同一個線程中,外層函數獲得鎖,內層依然有該鎖的代碼,不受影響。
public class Hello implements Runnable{
    ReentrantLock lock = new ReentrantLock();

    private void worker(){
        lock.lock();
        System.out.println("I'm worker: " + Thread.currentThread().getId());
        sayHello();
        lock.unlock();
    }
    private void sayHello(){
        lock.lock();
        System.out.println("Hello Word");
        lock.unlock();
    }

    @Override
    public void run() {
        worker();
    }

    public static void main(String[] args) {
        Hello hello = new Hello();
        new Thread(hello).start();
        new Thread(hello).start();
        new Thread(hello).start();
    }
}
  • 自旋鎖
    同一個線程兩次調用lock(),會導致第二次調用lock()位置進行自旋,產生死鎖。(不可重入鎖)
public class SpinLock {
    private AtomicReference cas = new AtomicReference();
    public void lock() {
        Thread current = Thread.currentThread();
        // 利用CAS
        while (!cas.compareAndSet(null, current)) {
            // DO nothing
        }
    }
    public void unlock() {
        Thread current = Thread.currentThread();
        cas.compareAndSet(current, null);
    }

}
  • 可中斷鎖
    在等待獲取鎖的過程中可中斷公平鎖
public class Hello implements Runnable{
    ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            lock.lockInterruptibly();
            System.out.println("Hello Word");
            Thread.sleep(2000);
            lock.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //正常
        Hello hello = new Hello();
        Thread t1 = new Thread(hello);
        t1.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();

//        InterruptedException異常
//        Hello hello = new Hello();
//        Thread t1 = new Thread(hello);
//        t1.start();
//        t1.interrupt();
    }
}
  • 公平鎖
    按等待獲取鎖的線程的等待時間進行獲取,等待時間長的優先獲取。(ReentrantLock默認是公平鎖
    非公平鎖
public class Hello implements Runnable{
    //非公平鎖
    ReentrantLock lock = new ReentrantLock(false);

    @Override
    public void run() {
        try {
            lock.lock();
            System.out.println("Hello Word" + Thread.currentThread().getName());
            Thread.sleep(2000);
            lock.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Hello hello = new Hello();
        Thread t1 = new Thread(hello);
        t1.setName("t1");
        t1.start();

        Thread t2 = new Thread(hello);
        t2.setName("t2");
        t2.start();

        Thread t3 = new Thread(hello);
        t3.setName("t3");
        t3.start();

    }
}    
  • 讀寫鎖
    對資源的讀寫的時候拆成兩個部分處理。讀的時候可以多線程一起讀,寫的時候必須同步寫。
public class Hello {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        Hello hello = new Hello();
        for (int i = 0; i < 3; i++) {
            new Thread(() ->{
                try {
//                    hello.read();
                    hello.put("Hello");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

    }

    public void put(Object object) throws InterruptedException {
        lock.writeLock().lock();
        System.out.println("我來寫東西了++++");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + " write " + object);
        lock.writeLock().unlock();
    }

    public void read() throws InterruptedException {
        lock.readLock().lock();
        System.out.println("我來讀東西了++++");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + " ++++++++++++");
        lock.readLock().unlock();
    }
}

偏向鎖、輕量級鎖、重量級鎖

偏向鎖: 它會偏向於第一個訪問鎖的線程,如果運行過程中,同步鎖只有一個線程訪問,不存在多線程競爭情況,線程不需要觸發同步鎖,系統會給線程加個偏向鎖。
輕量級鎖: 當有第二條線程加入競爭時,系統會把偏向鎖升級爲輕量鎖。
重量級鎖: 內置在java中被抽向爲監視器鎖(monitor)。調用成本非常高,包括系統調用引起的內核態與用戶切換、線程阻塞造成的線程切換等。(Syschronized

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章