当前位置: 首页 > news >正文

深圳网站建设开发/网站指数查询

深圳网站建设开发,网站指数查询,关键词优化推广排名软件,手机网站建设域名空间目录 尝试加锁 如果加锁不成功 重点 尝试加锁 最外层lock方法 ReentrantLock.class public void lock() {sync.lock();} 进来发现是个抽象方法 abstract static class Sync extends AbstractQueuedSynchronizer abstract void lock(); 底下有两个实现类,一个…

目录

尝试加锁

如果加锁不成功

重点


尝试加锁

最外层lock方法

ReentrantLock.class

public void lock() {sync.lock();}

进来发现是个抽象方法 

abstract static class Sync extends AbstractQueuedSynchronizer

abstract void lock();

底下有两个实现类,一个实现的公平锁,另一个为非公平锁 

我们看一下公平锁吧

static final class FairSync extends Sync

这里面可以看到入参为1 

final void lock() {acquire(1);}

AbstractQueuedSynchronizer

public final void acquire(int arg) {if (!tryAcquire(arg) &&  // 这个是尝试去获取锁acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

我们先去看怎么去获取锁的

protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}

列一下实现类

cas我理解就是通过线程的状态值和主内存中的状态值进行比较,如果相同则修改,如果不同则修改失败

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread(); // 获取当前线程int c = getState(); // 获取state的值if (c == 0) { // 为0的话,说明还没有线程持有这把锁// 因为你是公平锁,不能上去就去抢,要先去排队if (!hasQueuedPredecessors() && // 判断是否需要排队compareAndSetState(0, acquires)) { // 如果不需要排队就尝试通过cas获取锁setExclusiveOwnerThread(current); //获取成功,那么该锁归这个线程所有return true;}}else if (current == getExclusiveOwnerThread()) { // 如果已经被加锁,但是还是这个线程想去获取锁,那么则进行+1操作,然后获取锁成功// 如果进入到这个if,只能只有线程进来,不存在并发,不需要通过cas进行修改int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}

看一下是否需要排队的方法

  • 就是看头节点和尾节点是否相同,相同肯定就为空,还有些其他判断
public final boolean hasQueuedPredecessors() {// The correctness of this depends on head being initialized// before tail and on head.next being accurate if the current// thread is first in queue.Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());}

如果加锁不成功

就需要尝试入队了,走 && 另一个方法了

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

这边新建了一个互斥模式的节点,有互斥就会有共享模式,共享模式后面再说

private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}

节点内比较重要的属性:

  • waitStatus:这个是代表节点的生命状态,新建的节点这个值就为0
    • signal,cancelled,condition,propagate,0
  • pre、next:这两个就是双向链表的前后指针
  • thread:所有需要阻塞的线程肯定需要保存在某个位置等待唤醒

因为刚开始前后节点都为空,addwaiter方法里面第一个判断是不走的,走enq方法

private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node())) // 这里面就是把head指向新建的node// tail指向新建的nodetail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}

这里面能看到,是个空循环,就是为了让拿不到锁的线程入队成功,开始走第一个逻辑就是为了初始化,设置一个空节点,反正这里面干了下图这个事,怎么干的我也不知道(我知道了,就是新建的节点作为head,tail = head,就是tail也是指向新建的节点)

看第二个判断就是初始化之后走这个判断,t就是新建的那个节点,初始化的节点,那个cas方法就是为了让tail指向node,最后把前驱节点进行返回,没什么用

 接着回到这个方法,里面入参那是包裹着这个线程的节点以及1        

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor(); // 获得前驱节点if (p == head && tryAcquire(arg)) { // 如果前驱节点是头的话,就需要尝试去获取锁// 这里面就是获取锁成功,将该节点设为头节点setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}

这里面可以看一下setHead方法,就是相当于将该节点置空变为前驱节点(就是之前初始化的空节点)

private void setHead(Node node) {head = node;node.thread = null;node.prev = null;}

如果不是头节点或者没有获取锁成功,那么就走下面的这个逻辑

shouldParkAfterFailedAcquire

需要去获取前驱节点的waitStatus的状态,如果为0,就需要变为-1,变为一个可以被唤醒的状态

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.*/return true;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and* indicate retry.*/do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {/** waitStatus must be 0 or PROPAGATE.  Indicate that we* need a signal, but don't park yet.  Caller will need to* retry to make sure it cannot acquire before parking.*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}

然后被阻塞住

private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();
}

重点

acquireQueued(Node(currentThread), arg)
    节点阻塞之前还得再尝试一次获取锁:
    1,能够获取到,节点出队,并且把head往后挪一个节点,新的头结点就是当前节点
    2、不能获取到,阻塞等待被唤醒
        1.首先第1轮循环、修改head的状态,修改成sinal=-1标记处可以被唤醒.
        2.第2轮循环,阻塞线程,并且需要判断线程是否是有中断信号唤醒的!
        shouldParkAfterFailedAcquire(p, node)
    waitestate = 0 - > -1 head节点为什么改到-1,因为持有锁的线程T0在释放锁的时候,得判断head节点的waitestate是否!=0,如果!=0成立,会再把waitstate = -1->0,要想唤醒排队的第一个线程T1,T1被唤醒再接着走循环,去抢锁,可能会再失败(在非公平锁场景下),此时可能有线程T3持有了锁!T1可能再次被阻塞,head的节点状态需要再一次经历两轮循环:waitState = 0 -> -1

http://www.jmfq.cn/news/4922605.html

相关文章:

  • 做网站怎么去找客户/房地产估价师考试
  • 电子pcb做兼职的网站/端点seo博客
  • 济南能源建设网站/营销型网站建设服务
  • 在国外做盗版电影网站吗/企业站seo价格
  • wordpress导出app/东莞seo优化公司
  • 网站开发人才/海外广告投放渠道
  • 网站建设合同鉴于甲方委托乙方/商城全网推广运营公司
  • 如何做拼多多商城官网站/广东省疫情最新
  • 什么样的笔记本电脑适合网站开发/网站域名注册
  • 给设计网站做图/百度站长工具
  • 广州网站推广找谁/百度免费推广网站
  • 电商网站 设计/现在做百度推广有用吗
  • 酒店要做关于网站ppt怎么做/品牌推广策划方案怎么写
  • 在哪个网站做图片视频带音乐/免费的推广引流软件
  • 制作好的网站/关键词排名网络推广
  • 网站运营建设的培训/杭州网站优化体验
  • 汕头站扩建招标/河南网站设计
  • 网站有限公司免费/万网域名官网
  • 做淘宝客最大的网站是叫什么名字/外贸平台
  • 视频网站直播怎么做的/seo教程搜索引擎优化
  • 上海seo关键字推广/郑州网站建设专业乐云seo
  • 第18讲:商品模型 织梦网站系统 dedecms 教学课件/域名注册 阿里云
  • 百度网站建设是什么意思/前端优化网站
  • html网站模板 免费/写文章在哪里发表挣钱
  • 做公众号策划的网站/线上推广员是做什么的
  • 在线做爰视频网站/泉州seo按天收费
  • 秦皇岛网站/搜索词排行榜
  • 都昌县建设局网站/百度站长平台官网登录入口
  • 代做网站 猪八戒网/百度推广登录手机版
  • 广西建设学院官方网站/爱站工具包手机版