首页 Java分布式应用学习笔记06浅谈并发加锁机制分析

Java分布式应用学习笔记06浅谈并发加锁机制分析

举报
开通vip

Java分布式应用学习笔记06浅谈并发加锁机制分析 Java分布式应用学习笔记06浅谈并发加锁机制分析 刘岩 Email:suhuanzheng7784877@163.com Blog: suhuanzheng7784877.iteye.com 1. 前言 之前总结的多线程的调度、并发调度、线程加锁安全等等并发包底层大都使用了线程锁机 制。咱们通过锁的源码来看看 JDK如何将这些资源进行加锁限制的,怎么就能做到线程 集中等待后就唤醒主线程的。 2. 一段并发包源码 以下是java.util.concurrent.CyclicBarrier的底层代...

Java分布式应用学习笔记06浅谈并发加锁机制分析
Java分布式应用学习笔记06浅谈并发加锁机制 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 刘岩 Email:suhuanzheng7784877@163.com Blog: suhuanzheng7784877.iteye.com 1. 前言 之前总结的多线程的调度、并发调度、线程加锁安全等等并发包底层大都使用了线程锁机 制。咱们通过锁的源码来看看 JDK如何将这些资源进行加锁限制的,怎么就能做到线程 集中等待后就唤醒主线程的。 2. 一段并发包源码 以下是java.util.concurrent.CyclicBarrier的底层代码片段。 private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { ……………………省略 } finally { lock.unlock(); } } 在执行等待的时候,里面使用了 ReentrantLock对其进行资源加锁,保证在代码块中使 用变量、读写变量不会被别的线程打扰。 3. 轻量级锁ReentrantLock 基于以上程序我们就来看看ReentrantLock内部是如何工作的。ReentrantLock内部有个 Sync类,继承自 AbstractQueuedSynchronizer,基于 Sync又有 2个子类继承于它,而 ReentrantLock就是依靠这 2个 Sync子类为内核实现的。代码大家直接看 JDK源程序即 可。 ReentrantLock 的 lock()方法,它的加锁方法实际上是使用的内部静态类 Sync 的方法, 至于调用的是公平——FairSync 还是不公平的——NonfairSync,这个要看构建 ReentrantLock的时候的构造函数了。 NonfairSync 的加锁方法实现流程是这样的:首先基于 CAS——Compare and Swap 原则, 先将state从 0尝试变成1。如果设置成功了, 证明 住所证明下载场所使用证明下载诊断证明下载住所证明下载爱问住所证明下载爱问 了一个事实——此时此刻,没有其他 的线程持有该锁。则当前线程设置为 ExclusiveOwnerThread(独家拥有线程);那么如 果状态变量state设置不成功呢,则又揭示了一个事实,当前线程锁已经被其他线程所 持有,那么调用 acquire 方法,该方法首先先尝试再次获取状态 state,如果为 0了, 那么继续尝试设置状态为1。若成功则与此时无其他线程持有锁操作雷同。如果state依 然不为0,则判断当前线程是否为独家拥有线程变量——exclusiveOwnerThread,是的 话将state的值+1.如果不是,则将当前线程放入等待队列中挂起,挂起方法 public static void park(Object blocker) { 1 / 3 Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, 0L); setBlocker(t, null); } FairSync的 lock()方法和 NonfairSync大同小异。只不过它没有获取 state变量信息的 过程,直接是调用acquire(1)方法请求线程锁。 ReentrantLock的 unlock()方法,解锁的方法比较简单,不区分公平与不公平,都是获 取当前state值,之后减去释放锁的个数,减操作后结果如果为0,表示锁可以释放了。 通知 关于发布提成方案的通知关于xx通知关于成立公司筹建组的通知关于红头文件的使用公开通知关于计发全勤奖的通知 队列上的那些线程,唤醒队列头线程,进行run操作。 这些加锁、解锁操作很明显都离不开队列——AbstractQueuedSynchronizer的辅助操作, 将线程组织成为线程队列形式。 4. 读写锁ReentrantReadWriteLock 了解了 ReentrantLock 在加锁原理上使用了一把锁,一把钥匙开一把锁嘛~而如果遇到 大部分操作是读操作的、而写操作比较少的时候使用ReentrantLock未免有点“奢侈”。 使用ReentrantReadWriteLock——读写双锁进行读取和写入,在读多写少的场景下可以 提升不少性能。它的基本工作原理是这样的:当使用读锁进行lock的时候,就算是有其 他线程也进行读操作,而不是写操作的时候,线程不会阻塞,可以并行执行,和没有加 lock几乎是一样的。当调用写锁的lock方法时,无论其他线程是什么性质的(读、写), 都阻塞,所以这个双重锁适用于读操作频率较多、写操作频率较少的操作。咱们看个使用 例子 // 读写锁 static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); // 获得读锁-加锁 reentrantReadWriteLock.readLock().lock(); String str = listString.get(sum); reentrantReadWriteLock.readLock().unlock(); // 获得写锁-加锁 reentrantReadWriteLock.writeLock().lock(); String str = Thread.currentThread().getName() + "-- write:" + sum; listString.add(str); reentrantReadWriteLock.writeLock().unlock(); 因为一些特殊原因,不能将源码完整的场景全部给出,只能写出简单的使用关键的片段。 读锁的加锁源代码片段是 public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); } 2 / 3 写锁的加锁源码片段是 public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } 相比较而言,就是上面说过的一旦写锁加锁时发现有其他线程进行了操作,则将当前线 程放置于线程等待队列中——之后再唤醒。而读操作锁直接进行了共享线程,并发读取。 5. 总结 综合前面几篇线程调度、多线程并发计算等等,底层都是基于加锁、抽象线程等待队列 AbstractQueuedSynchronizer及其2个具体子类、CAS算法的综合体现。使用多线程并发 包后我们可以构建高可用和高计算能力的分布式系统。 注意:如果没有将解锁代码写到 finally块中,是有问题的!!如果发生了任何的运行 时异常,会向上抛,那么锁会永远不会解除,那么造成的后果大家一定知道了。 3 / 3
本文档为【Java分布式应用学习笔记06浅谈并发加锁机制分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_240278
暂无简介~
格式:pdf
大小:137KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2011-08-22
浏览量:22