Java并发包中锁原理剖析
2021-05-02 07:28
                         标签:读锁   获得   阻塞队列   可重入   使用   object类   countdown   查看   string    跟wait()不同! 引入了一个许可证的概念。 检测此时的线程是否拥有许可证,有的话。就通过,没有的话就阻塞。 LockSupport.park():在哪儿调用就是检查哪个线程 LockSupport.unpark(t):给t线程发一个许可证。 如果有许可证,直接返回 如果没有许可证,那就等一会再返回 讲blocker参数传入到阻塞线程中去 相对时间 准确时间 AbstractQueuedSynchronized:简称AQS,抽象同步队列;实现同步锁的基础组件。 并发包中的锁底层就是使用AQS实现的。    AQS是一个FIFO的双向队列,其内部通过节点head和tail记录队首和队尾元素,队列元素的类型是Node。 Node节点用来保存一条线程: 最终要的AQS中的state是实现不同锁的基础! AQS中有内部类ConditionObject类:每个对象对应一个条件队列(单向链表队列):其中放调用条件变量await方法后被阻塞的线程。 对于ReentrantLock来说:state指的是可重入锁的次数 对于ReetrantReadWriteLock来说:高十六位是:读的重入数;低十六位:写锁的重入数; 对于CountDownlatch来说:state用来表示计数器当前的值 根据state是否属于一个线程:操作state的方式分为独占式和共享式。 谁获得了锁,state从0---->1;假如重入获取,state+1;解锁:state-1; 没有获取到锁:放入AQS阻塞队列中 boolean release(int args)  获取锁,没有就讲线程保存到AQS的阻塞队列里头。 例如信号量Semaphore:多个线程去请求资源时通过CAS方式竞争资源,当一个线程获取到了资源后,另外一个线程再次去获取时如果当前资源还能满足它的需要,则当前线程只需要使用CAS方式获取即可。 boolean releaseShared(int args) void acquireShared(int arg):不响应中断 void acquireInterruptiblyShared(int arg):响应中断 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- 获取锁:都是CAS 失败:LockSupport.park()假如到AQS队列里头等待 释放:释放成功,LockSupport.unpar()唤醒一个,CAS获取锁咯。 上述的tryxx的方法AQS需要实现的子类自己写   例如:ReentrantReadWriteLock 读锁重写tryAcquireShared时,首先查看写锁是否被其它线程持有,如果有则直接返回false,否则使用CAS递增state的高16位; 释放读锁时:重写tryRealeaseShared时,在内部需要使用CAS算法把当前state的高16位减1.   isHeldExclusively():判断锁是被当前线程独占还是被共享。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 就是之前的哪个ConditionObject类 其实没什么难得,就是不在AQS的队列中等,在ConditionObject的队列中等。await和singal-------------》wait()和notify()差不多 当一个线程调用条件变量的signal方法时,会将条件队列的一个线程节点从条件队列中移到AQS的队列中,然后激活这个线程。 signalAll是将所有的线程放到AQS中 例如:生产者和消费者 有一个生产者A和两个消费者B.C 所以,在判断的时候用while,每次进来都判断一下。这样才能避免虚假唤醒。 重写tryAcquire(int acquires)、tryRelease(int releases)、newCondition()、isHeldExclusively() 假如是非公平锁: 公平锁 就是判断head指针的下一个节点是不是S,是的就冲了,不是就等等!,反正我是这么理解的         读写锁:维护了一个ReadLock和WriteLock 基于AQS实现 state高16位表示读状态 低16位标识写状态 如果当前没有线程获取到读锁和写锁,则当前线程可以获取到写锁然后返回。 如果当前线程有线程获取的读锁和写锁,写锁会被阻塞起来 重入+1 如果当前没有线程获得写锁,那就可以获取读锁 提供三种锁: 可以转换位写锁 不用加锁,只需要在使用的时候,判断一下有没有写锁!   Java并发包中锁原理剖析 标签:读锁   获得   阻塞队列   可重入   使用   object类   countdown   查看   string    原文地址:https://www.cnblogs.com/sicheng-li/p/13202563.html6.1LockSupport
void park()方法
void unpark(Thread thread)方法
LockSupport.parkNanos(long nanos)
LockSupport.park(Object blocker)方法
LockSupport.parkNanos(Object blocker, long nanos)
LockSupport.parkUnitl(Object blocker, long deadline)
大名鼎鼎的AQS

独占式
释放资源

获取资源
void acquire(int arg):不响应中断

void acquireInterruptibly(int arg):响应中断
共享式
释放资源

获取资源

成功:执行node节点入队操作


AQS---条件变量的支持
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("I am one");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println("I am one signal");
                    lock.unlock();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("I am two");
                condition.signal();
                System.out.println("I am two");
                lock.unlock();
            }
        }).start();
    }
    /**
     * I am one
     * I am two
     * I am two
     * I am one signal
     */
}

什么是虚假唤醒
手动实现基于AQS的锁
独占锁ReentrantLock原理



获取锁lock()





 
tryLock()方法


释放锁 void unlock()方法




ReentrantReadWriteLock原理

WriteLock
ReadLock
StampedLock
写锁WriteLock
悲观读锁readLock
乐观读锁tryOptimisticRead