天天看點

Java實作自定義自旋鎖

自旋鎖

1.空輪詢實作

  • 此處主要利用while空輪詢以及原子包的CAS
package com.gy.spinlock;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 利用空輪詢實作
 */
public class SpinLock01 {

    private AtomicInteger state = new AtomicInteger(0);


    public void lock() {
        while (!state.compareAndSet(0, 1)){

        }
    }

    public void unLock() {
        state.compareAndSet(1, 0);
    }
}

           

2. sleep提升性能

  • 第一種實作問題比較明顯,當我們的線程沒有獲得鎖之前都是空輪詢,此時我們可以讓沒有擷取鎖的線程停止
package com.gy.spinlock;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 利用空輪詢實作
 */
public class SpinLock01 {

    private AtomicInteger state = new AtomicInteger(0);


    public void lock() {
        while (!state.compareAndSet(0, 1)){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void unLock() {
        state.compareAndSet(1, 0);
    }
}

           

3. Unsafe提升性能

  • 第二種方式雖然能讓程式暫停但是sleep的時間是不好控制的,那麼這裡有沒有一種方式可以直接讓程式停止知道unlock的時候才被喚醒
  • park方法和unPark方法就能實作這樣的功能
  • 此處unLock處不一定就是unPark的線程獲得鎖
  • 此處加鎖解鎖是否同一線程并未處理,處理方式隻需要記錄加鎖線程解鎖時判斷即可
package com.gy.spinlock;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * 利用空輪詢實作
 */
public class SpinLock01 {

    private AtomicInteger state = new AtomicInteger(0);

    private Queue<Thread> queue = new LinkedList();


    public void lock() {
        while (!state.compareAndSet(0, 1)){
            queue.add(Thread.currentThread());
            LockSupport.park();
        }
    }

    public void unLock() {
        state.compareAndSet(1, 0);
        LockSupport.unpark(queue.poll());
    }
}