我所認識的鎖-總結

1、公平鎖:多個線程之間可以按照線程申請鎖的順序獲取鎖;

2、非公平鎖:多個線程之間獲取鎖的順序不一定按照申請鎖的順序獲得;Synchronized、ReentrantLock默認是非公平鎖,後者可以通過構造參數獲取公平鎖。

3、可重入鎖又叫遞歸鎖:是指在一個同步方法內部調用另外一個同步方法時,獲得的鎖是同一把鎖,避免死鎖;舉例如下:

public class TestLock {

    public synchronized void hello() {
        System.out.println(Thread.currentThread().getName() + "\t 測試遞歸鎖");
        //實現的效果就是hello()方法和world()方法總是總一個線程、具有原子性
        world();
    }

    public synchronized void world() {
        System.out.println(Thread.currentThread().getName() + "\t 測試遞歸鎖2");
    }

    public static void main(String[] args) {
        TestLock tl = new TestLock();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                tl.hello();
            }, String.valueOf(i)).start();
        }
    }

}

打印結果:

0	 測試遞歸鎖
0	 測試遞歸鎖2
6	 測試遞歸鎖
6	 測試遞歸鎖2
4	 測試遞歸鎖
4	 測試遞歸鎖2
5	 測試遞歸鎖
5	 測試遞歸鎖2
3	 測試遞歸鎖
3	 測試遞歸鎖2
2	 測試遞歸鎖
2	 測試遞歸鎖2
1	 測試遞歸鎖
1	 測試遞歸鎖2
9	 測試遞歸鎖
9	 測試遞歸鎖2
8	 測試遞歸鎖
8	 測試遞歸鎖2
7	 測試遞歸鎖
7	 測試遞歸鎖2
hello方法和world方法總是一起執行

4、自旋鎖:是指獲取鎖的線程不會立即阻塞,而是利用循環比較的方式去獲取鎖,好處就是減少上下文切換,缺點是循環比較會消耗cpu的性能,舉例如下:

public class TestLock2 {

    //利用在這個原子類中存入當前線程,爲獲取鎖,否則自循環等待其他線程釋放鎖以獲得鎖
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public void lock() {
        Thread thread = Thread.currentThread();
        //比較替換成功取反爲false跳出循環
        while (!atomicReference.compareAndSet(null, thread)) {

        }
        System.out.println(thread.getName() + "\t come in");

    }

    public void unlock() {
        Thread thread = Thread.currentThread();
        //釋放鎖就是將值爲當線程的內存值更新爲null,好讓下一個線程獲取鎖
        atomicReference.compareAndSet(thread, null);
        System.out.println(thread.getName() + "\t come out");
    }

    public static void main(String[] args) {
        TestLock2 tl = new TestLock2();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                tl.lock();
                try {
                    //模擬每個線程進來需要消耗1秒鐘
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    tl.unlock();
                }
            }, String.valueOf(i)).start();
        }
    }
}

打印結果:

0	 come in
0	 come out
6	 come in
6	 come out
4	 come in
4	 come out
2	 come in
2	 come out
9	 come in
9	 come out
8	 come in
8	 come out
7	 come in
7	 come out
1	 come in
1	 come out
5	 come in
5	 come out
3	 come in
3	 come out

取得了獲取鎖,釋放鎖的效果

5、獨佔鎖:一次只能被一個線程擁有;共享鎖:一次可以被多個線程共有;其中讀讀是共享,寫讀、讀寫、寫寫都互斥

舉例如下:

public class TestLock3 {

    Map<String, Object> params = new HashMap<>();
    ReentrantReadWriteLock rw = new ReentrantReadWriteLock();

    /**
     * 讀共享
     *
     * @param k
     * @return
     */
    public Object get(String k) {
        rw.readLock().lock();
        Object value = null;
        try {
            value = params.get(k);
            System.out.println(Thread.currentThread().getName() + "\t 讀到的值" + value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rw.readLock().unlock();
        }
        return value;
    }

    /**
     * 寫互斥
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setParams(String key, Object value) {
        rw.writeLock().lock();
        if (value == null) {
            return false;
        }
        try {
            params.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t key=" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rw.writeLock().unlock();
        }
        return true;
    }

    public static void main(String[] args) {
        TestLock3 testLock3 = new TestLock3();
        //多線程寫
        for (int i = 0; i < 10; i++) {
            final int a = i;
            new Thread(() -> {
                testLock3.setParams(String.valueOf(a), UUID.randomUUID().toString().substring(0, 3));
            }, String.valueOf(i)).start();
        }

        //先讓寫線程進行
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //多線程讀
        for (int i = 0; i < 10; i++) {
            final int b = i;
            new Thread(() -> {
                testLock3.get(String.valueOf(b));
            }, String.valueOf(i)).start();
        }
    }

}

 

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