Luminous areas of Java to bring you into God's way (forty-five) good

Luminous Preamble:

 

Profound understanding ~

The road of life is forced to come out, do not force myself to one, you never know how much they can do things.

Cut off the escape route, they will naturally think of ways to find a way out;

Cut off the illusion, we will work hard.

Forced himself out of the first step, the second step, third step is much easier.

If you do not force yourself, laziness will gradually corroded his heart, once the lofty will be wiped out, and the value of life will be greatly reduced.

 

 

 

 

 

 

 

 

 

text:

                           Tao Yu technique / procedure to identify channels

ReentrantLock和synchronized

We found that in actual development, look at the situation, which is not a particularly large number of use

I prefer synchronized


Unlike ssh and concurrent programming ssm

What combat, give what you develop a management system or landing

 

Interview rocket science, practical work tighten the screws

 

 

 

 

 

 

 

Concurrent programming really want to get to understand

Still need to see the source code

 

Source ReentrantLock detailed interpretation

AbstractQueuedSynchronizer (AQS source interpretation)

You can think about the targeted understanding of the above issues

Above this figure very vivid description of the various relationships

Here mention: Software engineering is a science, a lot of things we need programmers to practice, what spring, springboot, springcloud, we can easily entry through training or self-study

However, concurrent programming requires deep inside to the next can have experience, so you need to practice

Did not see the source code, a lot of things are useless hearsay ~~~


 

Windows is not open source

A lot of things, we have to learn linux

 

 

 

   

    First it: Sync: AQS is to provide the tools to achieve similar adapter, provides an abstraction of the lock (), to facilitate the rapid creation of non-fair locks.
    : FairSync (fair lock) the same order as the order of acquisition thread lock and call lock () is, FIFO. That is, first-served basis


    Order unrelated thread gets the lock and call lock () in order to grab CPU time slice scheduling: NoFairSync (unfair lock).


ReentrantLock in an important way: Here, we need to mention to mention

Constructor: constructor with no arguments, we can create a non-default realize → fair locks; however it ~ ~

There arg constructor, and when the fair == true, create a fair lock.
 


// 这里,我们可以看到
//维护了一个Sync,对于锁的操作
//我们发现,都交给sync来处理
    private final Sync sync;   
 
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

这里需要提一提:获取资源资源(锁)的方法

请求都是交给Sync来调度的。

    //首先呢
//    可以发现:请求锁资源,会阻塞且不处理中断请求,
    //这里,我们做一个假设,如果没有调用unLock(),则会一直被阻塞。
    public void lock() {
        sync.lock();
    }
//其次呢
//很重要的一个概念
    //有一种情况:线程在请求lock并被阻塞时
//这里,如果被interrupt,则此线程会被唤醒并被要求处理
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
//我们继续往下面看
//
    //尝试获取锁,默认获取的是非公平锁,失败后不会阻塞
    //直接返回true或false
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    //这里,我们需要提一提 → 重载方法,在规定时间内获取锁,获取不到则返回false
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

嗯唔~~      锁肯定需要释放,我们释放资源(锁)的方法:

不管是公平还是非公平锁,我们都会调用AQS.release(1)这个方法~~

给当前线程持有锁的数量-1。

//释放锁,给当前线程持有锁的数量-1  
  public void unlock() {
        sync.release(1);
    }

 

 

嗯唔~~

那个:主要讲非公平锁与公平锁获取资源的方法,因为释放资源的逻辑是一样的。

Sync来获取资源

我们需要知道:sync中定义了获取资源的总入口。但是呢,具体的调用还是看实现类是什么。

//调用的方法
abstract void lock();

 

我们看一看:非公平锁获取资源

嗯唔,看一看lock():获取锁时调用AQS的CAS方法,是阻塞的。

如果获取成功,则把当前线程设置为锁的持有者;如果获取失败,则通过AQS.acquire()获取锁。

 

我们程序员之前通过AQS源码详细解读,了解到acquire()中使用了模板模式,调用子类的tryAcquire()尝试获取锁

 

如果tryAcquire()返回false,则进入等待队列自旋获取,这之后呢,再判断前驱的waitStatus【这是一个很重要的概念】,判断是否需要被阻塞等。
 

 

tryAcquire():走的是Sync.nofairTryAcquire()。

    
//我们看一看这个代码嗯
//tryAcquire  布尔类型
    protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

我们再来看看下面这一段代码:

 

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
//这里,我们备注一个注释
            //state是0,锁处于空闲状态,使用CAS获取
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    //获取成功后,当前线程就是锁的持有者
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //这里呢,获取失败则先判断当前线程是否是锁的持有者
            //这里很重要,也是ReentrantLock实现可重入的原因
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                //可以看出源码设计者的厉害之处,考虑到了锁溢出的情况
                if (nextc < 0) 
                    throw new Error("Maximum lock count exceeded");
                //这里呢          我们将当前线程持有的锁+1
                setState(nextc);
                return true;
            }
            return false;
        }

 

nonfairTryAcquire(int acquires):这是什么意思呢,表示如果锁空闲,则用CAS修改state;

 

如果锁被占用,则判断占有者是不是自己,实现可重入。

那么~~          最终没有获取锁到就返回false。


 

下面,我们再看看:如何运用公平锁获取资源

lock():也是阻塞的。这里需要注意一下:

与非公平锁的区别是,我们呢~~

不能直接通过CAS修改state,而是直接走AQS.acquire()。

 

//方法差不多就是这样嗯
//参数为1     
   final void lock() {
            acquire(1);
        }

 

这里,我们看一看          →        tryAquire():与非公平锁类似,AQS.acquire()会调用这个钩子方法。

但是呢,我们发现多判断了hasQueuedPredecessors(),判断当前节点在等待队列中是否有前驱节点,如果有,则说明有线程比当前线程更早的请求资源,根据公平性

 

嗯唔~~         当前线程请求资源失败;如果当前节点没有前驱节点,才有做后面的逻辑判断的必要性。
 


 

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //下面这段源代码,很多老师都讲过该如何理解
                //我们可以看一下
                //!hasQueuedPredecessors()判断等待队列中是否有前驱节点,没有则尝试获取锁
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
//下面该如何理解呢,我们看一下
            //实现可重入
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

 

下面,我们看一下:

ReentrantLock有三种获取锁的方法,lock(),tryLock(),lockInterruptibly()。

 

这里我们提一提获取资源   →  tryLock():走的还是sync的方法,主要是在指定时间内获取锁,直接返回结果。


    
// tryLock():走的还是sync的方法,主要是在指定时间内获取锁,直接返回结果。
public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    
//我们看看下面这一段代码
//看看如何理解
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
//tryAcquireNanos():如果调用tryLock的规定时间内尝试方法,就会调用该方法
//挺有意思的
//这里,我们先判断是否中断,然后尝试获取资源,否则进入AQS.doAcquireNanos()
//在规定时间内自旋拿资源,[这里注意一下:自旋的次数是由计算机学者决定的]
//拿不到则挂起再判断是否被中断。
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }

嗯唔~~         这里我们看一下:lockInterruptibly()--获取锁时响应中断

lockInterruptibly():交给了调度者sync执行。

    //我们看一下这个方法

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

 

我们看一下:acquireInterruptibly()    →    嗯唔~~这里当尝试获取锁失败后,之后,我们就进行阻塞可中断的获取锁的过程。

这里,我们调用AQS.doAcquireInterruptibly()这个方法

很厉害嗯~~


 

  //我们看下下面这个方法
// Thread.interrupted() 阻塞

   public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

我们可以知道:公平锁与非公平锁的释放都是一样的。

我们可以知道:ReentrantLock.release()调用的是sync.release(1)。

所以呢:本质还是进入AQS.release(1),下面看看其中的tryRelease()这个钩子方法如何实现。


嗯唔~~:Sync释放资源

tryRelease():尝试释放锁,彻底释放后返回true。
 

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            //需要注意一下:释放锁必须保证当前线程是锁的持有者
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            //注意看下状态值
            //如果释放后状态值为0,则彻底释放,持有者被设置为空
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            //嗯唔
            //设置释放后的state
            setState(c);
            return free;
        }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

发布了1477 篇原创文章 · 获赞 281 · 访问量 14万+

Guess you like

Origin blog.csdn.net/weixin_41987706/article/details/103850203