java并发编程-ReentranLock详解

致敬大师,致敬未来的你
生命不止,学习不息,运动不息
Life does not stop, learning does not stop, movement does not stop

ReentranLock使用

ReentranLock使用很简单,就是把需要上锁的代码,用lock与unlock包裹就行,就像下边的代码

import java.util.concurrent.locks.ReentrantLock;

public class Test {

    //默认不公平锁
    static ReentrantLock lock = new ReentrantLock(true);

    static void insert(){
        try{
            lock.lock();
            //模拟业务代码执行
            System.out.println("我被锁了" + Thread.currentThread().getId());
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        //模拟多线程执行
        new Thread(()->{
            insert();
        }).start();
        new Thread(()->{
            insert();
        }).start();
        new Thread(()->{
            insert();
        }).start();
    }
}

认识公平锁和非公平锁、自旋

ReentranLock在使用上分为公平锁和非公平锁

公平锁

卖饭窗口就是锁,人相当于一个个线程,每次接待一个人,后边每个人都在排队,这就是公平锁
公平锁

非公平锁

非公平锁就相当于一群人在抢这个卖饭窗口,谁抢到谁就能买饭
非公平锁

自旋

自旋就相当于一个死循环,在每次循环的时候,就判断一下条件,是否要跳出这个死循环

int a = 0;
while(true){
	if(a%2 == 0){
		//当满足次条件时,跳出循环,否则继续循环
	     break;
	 }
	 if(a%3 == 0){
	 	//当满足次条件时,跳出循环,否则继续循环
	     break;
	 }
	 a++;
 }

ReentranLock详解

ReentranLock构造方法

构造方法分为两种,一种是无参构造方法,一种是有参构造方法

static ReentrantLock lock1 = new ReentrantLock();		//无参构造方法
static ReentrantLock lock = new ReentrantLock(true);	//有参构造方法
无参构造方法

无参构造方法默认使用非公平锁
源码片段:

    public ReentrantLock() {
        sync = new NonfairSync();
    }
有参构造方法

有参构造方法根据用户去指定使用公平锁还是非公平

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
构造方法总结

ReentranLock实例化对象时,实际使用了它的内部类
构造方法总结
而点开Sync,可以看到这个类继承了AbstractQueuedSynchronizer,也就是我们平时所说的AQS
Sync又有两个子类NonfairSyncFairSync ,如下代码段所示

abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync
static final class FairSync extends Sync

公平锁详解

以下基于jdk1.8

公平锁流程

大家都知道公平锁到底是怎么回事了,那么公平锁的简单流程呢,
公平锁流程

retrantLock源码各种定义
最小单位-node节点

最小节点全类名为java.util.concurrent.locks.AbstractQueuedSynchronizer.Node
其中主要属性解释如下:
Node SHARED : shared模式
Node EXCLUSIVE : 独占模式
Node nextWaiter: 队列模式,或者说节点类型,值为上边两个的值,SHARED 或者 EXCLUSIVE
Thread thread : 存储当前节点对应的线程
int waitStatus : 同步状态、锁类型、节点类型,存储的是下一个节点的,所以说,空队列添加第一个节点时,会构建一个空的node先添加进去
     ~~~~     所以这就是为什么Node用双向链表它把当前节点的状态放到了前一个节点中
state类型如下所示

/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED =  1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL    = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;

Node prev : 上一个节点
Node next : 下一个节点
retrantLock中,waitStatus的值为SIGNALnextWaiterEXCLUSIVE

等待队列

在AQS也就是java.util.concurrent.locks.AbstractQueuedSynchronizer类中,用了两个属性维持着这个队列
在初始化retrantLock时,不会对次队列进行初始化,当插入第一个节点时,才会初始化

//头节点
private transient volatile Node head;
//尾节点
private transient volatile Node tail;
加锁图解

添加第一个节点
添加第一个节点
添加第二个节点
添加其他节点

以下为整个retrantLock代码流程
在这里插入图片描述

解锁流程

使用park.unpark()唤醒nexNode
如果nextNode为空,则从尾节点开始遍历,找到不为空的节点(不太清楚为什么要这么做)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值