手写可重入锁(Lock)

  • 可重入锁
    lock 来保证原子性。
    什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。
    可通过CAS来实现原子操作
    CAS(Compare and Swap):
    CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。
    CAS主要通过compareAndSwapXXX()方法来实现,而这个方法的实现需要涉及底层的unsafe类
    unsafe类: java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作。

顺便记录下java中实现原子操作的类

  1. AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
  2. AtomicLongFieldUpdater:原子更新长整型字段的更新器
  3. AtomicStampedReference:原子更新带有版本号的引用类型。该类将整型数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。
  4. AtomicReference :原子更新引用类型
  5. AtomicReferenceFieldUpdater :原子更新引用类型里的字段
  6. AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和应用类型
  7. AtomicIntegerArray :原子更新整型数组里的元素
  8. AtomicLongArray :原子更新长整型数组里的元素
  9. AtomicReferenceArray : 原子更新引用类型数组的元素
  10. AtomicBooleanArray :原子更新布尔类型数组的元素
  11. AtomicBoolean :原子更新布尔类型
  12. AtomicInteger: 原子更新整型
  13. AtomicLong: 原子更新长整型

  • 自定义不可重入锁
public class Lock {

    private boolean isLocked = false;

    public synchronized void lock() throws InterruptedException
    {
        while (isLocked){
            wait();
        }
        isLocked = true;
    }

    public synchronized void unlock(){
        isLocked = false;
        notify();
    }
}
------------------------------------------------------
public class UnLockAgin {

    Lock lock = new Lock();

    public void frist() throws InterruptedException{
        lock.lock();
        add();
        lock.unlock();
    }

    public void add() throws InterruptedException {
        lock.lock();
        // todo
        lock.unlock();
    }
}

当调用frist()方法时,获得了锁,这时就无法再调用add()方法,这时必须先释放锁才能调用,所以称这种锁为不可重入锁,也叫自旋锁


  • 可重入锁
    实现Lock 接口,自定义锁
public class MyLock implements Lock {

    // atomic 类具有原子性
    AtomicReference<Thread> owner = new AtomicReference<>();
    //等待列表,存放等待的线程
    public LinkedBlockingDeque<Thread> waiter = new LinkedBlockingDeque<>();

    //加锁
    @Override
    public void lock() {
        //进行比较交换
        while( !owner.compareAndSet(null,Thread.currentThread()))
        {
            //未抢到锁,将当前线程,加入等待队列。
            waiter.add(Thread.currentThread());
            //让线程等待
            LockSupport.park();
            // 锁已经被释放,将当前线程从等待线程队列中移除
            waiter.remove(Thread.currentThread());
        }
    }

    //释放锁
    @Override
    public void unlock() {
        //判断当前线程是否持有锁,有,则释放锁。
        if( owner.compareAndSet(Thread.currentThread(),null))
        {
            //通知等待的队列唤醒
            Object[] objects = waiter.toArray();//数组化

            for (Object obj:objects ) {
                // 唤醒线程
                LockSupport.unpark((Thread)obj);
            }
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
  • 测试
public class UnLockAgin {

    MyLock lock = new MyLock();//引入可重入锁

    int i = 0;
    int j = 0;

    public void incr(){
        //加锁
        lock.lock();
        try {
            i++;
            j++;
        }
        finally {
            lock.unlock();//释放锁
        }
    }

    public static void main(String[] args) throws InterruptedException {
        UnLockAgin lockAgin = new UnLockAgin();

        for (int i = 0; i < 5; i++) {
            new Thread(()-> {
                //每个线程执行1000 次
                for (int j = 0; j < 1000; j++) {
                    lockAgin.incr();
                }
            }).start();
        }

        Thread.sleep(1000);
        System.out.println(lockAgin.i);
        System.out.println(lockAgin.j);
    }

}

手写可重入锁(Lock)