Lock

简介

Lock位于 java.util.concurrent 包下,本质上Lock仅仅是一个接口。可以实现公平锁和非公平锁,默认非公平锁。

在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock、ReadWriteLock(实现类ReentrantReadWriteLock)

包含方法:

//尝试获取锁,获取成功则返回,否则阻塞当前线程
void lock(); 

//尝试获取锁,线程在成功获取锁之前被中断,则放弃获取锁,抛出异常 
void lockInterruptibly() throws InterruptedException; 

//尝试获取锁,获取锁成功则返回true,否则返回false 
boolean tryLock(); 

//尝试获取锁,若在规定时间内获取到锁,则返回true,否则返回false,未获取锁之前被中断,则抛出异常 
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 

//释放锁
void unlock(); 

//返回当前锁的条件变量,通过条件变量可以实现类似notify和wait的功能,一个锁可以有多个条件变量
Condition newCondition();

实现原理

观察ReentrantLock把所有Lock接口的操作都委派到一个Sync类上,该类继承了AbstractQueuedSynchronizer

static abstract class Sync extends AbstractQueuedSynchronizer  

Sync又有两个子类:

final static class NonfairSync extends Sync  
 
final static class FairSync extends Sync 

核心实现依赖java.util.concurrent.AbstractQueuedSynchronizer类。

内部维护一个volatile修饰的state状态变量和CLH虚拟队列(双向链表)

公平锁: AQS内部维护着一个FIFO的队列,即CLH虚拟队列(先进先出双向链表),AQS把所有的请求线程构成一个CLH队列;"双向链表" + "int类型状态state";
非公平锁: 无视队列,直接CAS尝试获取锁。

 

 

①: 当线程调用 lock() 时,通过CAS操作修改 state 值为 1 来判断是否获取到锁,修改成功则获得锁;
②: 失败则再次尝试一次 CAS 获取锁,如果 state 状态是 0 那么 CAS 设置为 1;
③: 如果 state 状态既不是 0 也不是自身线程持有则把当前线程构造成一个 Node 节点,如果state状态是1且是自身线程则将 state 当前值 +1;
④: 把当前线程 Node 以 CAS的方式放入队列中,行为上线程阻塞,内部自旋获取状态 (acquireQueued的主要作用是把已经追加到队列的线程节点进行阻塞,但阻塞前又通过tryAccquire重试是否能获得锁,如果重试成功能则无需阻塞,直接返回。)
⑤: 线程释放锁,唤醒队列第一个节点,参与竞争。重复上述。
 

锁实现(加锁)

AbstractQueuedSynchronizer会把所有的请求线程构成一个CLH队列,当一个线程执行完毕(lock.unlock())时会激活自己的后继节点,但正在执行的线程并不在队列中,而那些等待执行的线程全部处于阻塞状态,经过调查线程的显式阻塞是通过调用LockSupport.park()完成,而LockSupport.park()则调用sun.misc.Unsafe.park()本地方法,再进一步,HotSpot在Linux中通过调用pthread_mutex_lock函数把线程交给系统内核进行阻塞;如果已经存在Running线程,则新的竞争线程会被追加到队尾,具体是采用基于CAS的Lock-Free算法,因为线程并发对Tail调用CAS可能会导致其他线程CAS失败,解决办法是循环CAS直至成功。

一个虚拟队列,不存在队列实例,仅存在节点之间的前后关系;当有线程竞争锁时,该线程会首先尝试获得锁,这对于那些已经在队列中排队的线程来说显得不公平,这也是非公平锁的由来。

 

区别

1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized可对实例方法、静态方法和代码块加锁,Lock针对线程;
3.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
4.synchronized会自动释放锁(a 线程执行完同步代码会释放锁; b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
5.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
6.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
7.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
 

自定义Lock

public class MyCustomLock implements Lock {

    private Helper helper = new Helper();

    //定义内部类继承AQS
    private class Helper extends AbstractQueuedSynchronizer{
        //获取锁
        @Override
        protected boolean tryAcquire(int arg) {
            int state = getState();
            if (state == 0){
                if (compareAndSetState(0,arg)){
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
            }else if(getExclusiveOwnerThread() == Thread.currentThread()){
                setState(getState() + arg);
                return true;
            }
            return false;
        }

        //释放锁
        @Override
        protected boolean tryRelease(int arg) {
            int state = getState()-arg;
            boolean flag = false;
            //判断state是否为0,为0则表示释放锁
            if (state == 0){
                setExclusiveOwnerThread(null);
                setState(state);
                return true;
            }
            setState(state);
            return false;
        }

        protected Condition newCondition(){
            return new ConditionObject();
        }
    }

    @Override
    public void lock() {
        helper.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        helper.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return helper.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return helper.tryAcquireNanos(1,unit.toNanos(time));
    }

    @Override
    public void unlock() {
        helper.release(1);
    }

    @Override
    public Condition newCondition() {
        return helper.newCondition();
    }

}

 

posted @ 2020-10-14 11:32  柒月丶  阅读(318)  评论(0)    收藏  举报