java锁实现

我们都将第三方库用作开发的正常部分。 通常,我们无法控制其内部。 JDK随附的库是一个典型示例。 这些库中的许多库都使用锁来管理争用。
JDK锁具有两种实现。 一个使用原子CAS样式指令来管理索赔过程。 CAS指令往往是最昂贵的CPU指令类型,并且在x86上具有内存排序语义。 锁通常是无竞争的,这会导致可能的优化,从而可以使用避免使用原子指令的技术将锁偏向无竞争的线程。 这种偏向使得理论上的锁定可以被同一线程快速重新获得。 如果该锁最终被多个线程争用,则该算法将从被偏向的状态恢复,并使用原子指令退回到标准方法。 偏向锁定已成为Java 6的默认锁定实现 。
在遵守单一作者原则时,偏向锁定应该是您的朋友。 最近,当使用套接字API时,我决定测量锁定成本,并对结果感到惊讶。 我发现我的无竞争线程所产生的开销比锁期望的要多。 我汇总了以下测试,以比较Java 6中当前可用的锁实现的成本。
考试
为了进行测试,我将在锁中增加一个计数器,并增加锁中竞争线程的数量。 对于Java可用的3种主要锁实现,将重复此测试:
  1. Java语言监视器上的原子锁定
  2. Java语言监视器上的偏向锁定
  3. Java 5中随java.util.concurrent包引入的ReentrantLock 。
我还将在最新的3代Intel CPU上运行测试。 对于每个CPU,我将执行测试,直到核心计数将支持的最大并发线程数。
该测试是在64位Linux(Fedora Core 15)和Oracle JDK 1.6.0_29上进行的。

代码

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CyclicBarrier;import static java.lang.System.out;public final class TestLocks implements Runnable
{public enum LockType { JVM, JUC }public static LockType lockType;public static final long ITERATIONS = 500L * 1000L *1000L;public static long counter = 0L;public static final Object jvmLock = new Object();public static final Lock jucLock = new ReentrantLock();private static int numThreads;private static CyclicBarrier barrier;public static void main(final String[] args) throws Exception{lockType = LockType.valueOf(args[0]);numThreads = Integer.parseInt(args[1]);runTest(numThreads); // warm upcounter = 0L;final long start = System.nanoTime();runTest(numThreads);final long duration = System.nanoTime() - start;out.printf("%d threads, duration %,d (ns)\n", numThreads, duration);out.printf("%,d ns/op\n", duration / ITERATIONS);out.printf("%,d ops/s\n", (ITERATIONS * 1000000000L) / duration);out.println("counter = " + counter);}private static void runTest(final int numThreads) throws Exception{barrier = new CyclicBarrier(numThreads);Thread[] threads = new Thread[numThreads];for (int i = 0; i < threads.length; i++){threads[i] = new Thread(new TestLocks());}for (Thread t : threads){t.start();}for (Thread t : threads){t.join();}}public void run(){try{barrier.await();}catch (Exception e){// don't care}switch (lockType){case JVM: jvmLockInc(); break;case JUC: jucLockInc(); break;}}private void jvmLockInc(){long count = ITERATIONS / numThreads;while (0 != count--){synchronized (jvmLock){++counter;}}}private void jucLockInc(){long count = ITERATIONS / numThreads;while (0 != count--){jucLock.lock();try{++counter;}finally{jucLock.unlock();}}}
}

编写测试脚本:

设置-x
对于{1..8}中的i; 做Java -XX:-UseBiasedLocking TestLocks JVM $ i; 做完了
对于{1..8}中的i; 做Java -XX:+ UseBiasedLocking TestLocks JVM $ i; 做完了 对于{1..8}中的i; 做Java TestLocks JUC $ i; 做完了

结果

图1
图2
图3
在现代英特尔处理器上,偏置锁定不再应该是默认的锁定实现。 我建议您使用-XX:-UseBiasedLocking JVM选项来衡量应用程序和实验的性能,以确定是否可以从无竞争情况下使用基于原子锁的算法中受益。

观察结果
  1. 在无竞争的情况下,有偏锁比原子锁贵10%。 似乎对于最近的CPU代来说,原子指令的成本比偏向锁的必要内务处理要少。 在Nehalem之前,锁定指令会在内存总线上声明一个锁定以执行这些原子操作,每个操作都将花费100个以上的周期。 从Nehalem开始,原子指令可以在CPU内核本地进行处理,并且在执行内存排序语义时不需要等待存储缓冲区为空时,通常只需花费10-20个周期。
  2. 随着争用的增加,无论线程数如何,语言监视器锁定都会Swift达到吞吐量限制。
  3. 与使用同步的语言监视器相比,ReentrantLock提供了最佳的无竞争性能,并且随着争用的增加,扩展性也显着提高。
  4. 当2个线程竞争时,ReentrantLock具有降低性能的奇怪特征。 这值得进一步调查。
  5. 当竞争线程数较少时,Sandybridge遭受原子指令增加的延迟 ,这在上一篇文章中已详细介绍。 随着竞争线程数的不断增加,内核仲裁的成本趋于占主导地位,而Sandybridge在提高内存吞吐量方面显示出其优势。
结论
在开发自己的并发库时,如果无锁替代算法不是可行的选择,则建议使用ReentrantLock而不是使用synced关键字,因为它在x86上具有明显更好的性能。
更新2011年11月20日
Dave Dice指出,未对JVM启动的前几秒中创建的锁实施偏向锁。 我将在本周重新运行测试并发布结果。 我收到了更多质量反馈,表明我的结果可能无效。 微型基准测试可能会很棘手,但是在大型环境中衡量自己的应用程序的建议仍然存在。
考虑到Dave的反馈,可以在此后续博客中查看测试的重新运行。
参考:来自我们的JCG合作伙伴 Martin Thompson的Java锁实现,来自Mechanical Sympathy博客。

翻译自: https://www.javacodegeeks.com/2012/07/java-lock-implementations.html

java锁实现

java锁实现_Java锁实现相关推荐

  1. java 全局变量 加锁_Java锁机制(一)synchronized

    进行多线程编程的时候,需要考虑的是线程间的同步问题.对于共享的资源,需要进行互斥的访问.在Java中可以使用一些手段来达到线程同步的目的: 1. synchronized 2. ThreadLocal ...

  2. java锁原理_Java锁原理学习

    Java锁原理学习 为了学习Java锁的原理,参照ReentrantLock实现了自己的可重入锁,代码如下: 先上AQS的相关方法: // AQS = AbstractQueuedSynchroniz ...

  3. java全局变量加锁_Java锁Synchronized,对象锁和类锁举例

    4. 同步加锁的是对象,而不是代码.因此,如果你的类中有一个同步方法,这个方法可以被两个不同的线程同时执行,只要每个线程自己创建一个的该类的实例即可. 5. 不同的对象实例的synchronized方 ...

  4. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  5. java架构升级_java架构之路(多线程)synchronized详解以及锁的膨胀升级过程

    上几次博客,我们把volatile基本都说完了,剩下的还有我们的synchronized,还有我们的AQS,这次博客我来说一下synchronized的使用和原理. synchronized是jvm内 ...

  6. java 对变量加锁_Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁...

    乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用. 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会 ...

  7. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  8. java 锁_Java 锁之我见

    今天我们来聊聊 Java 里面的各种锁:偏向锁.轻量级锁.重量级锁,以及三个锁之间是如何进行锁膨胀的. 众所周知,线程阻塞带来的上下文切换的代价是很大的,Java 为了尽量减少上下文的切换从而引入了更 ...

  9. java lock 对象_Java并发编程锁系列之ReentrantLock对象总结

    Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...

最新文章

  1. Cell子刊:大鱼大肉吃三天,体重未动大脑先变,不仅发胖还会发炎
  2. 十一、Python异常处理
  3. Anbox 和 LXC 代码规模
  4. Thread.sleep还是TimeUnit.SECONDS.sleep
  5. trie树查找前缀串_Trie数据结构(前缀树)
  6. 一文简介常见的机器学习算法
  7. keras demo - fashion_mnist
  8. 计算机科学导论实验,《计算机科学导论》实验.doc
  9. 教育部双一流计算机科学与技术,双一流大学及学科详情.pdf
  10. 笔记本硬盘调研 更换及启动盘设置
  11. 如何给国外老师写邮件
  12. 你要找的cocos面试答案都在这里了!
  13. html开发android,使用HTML5开发Android本地应用(一)
  14. Android 框架学习1:EventBus 3.0 的特点与如何使用
  15. 【一篇无聊的影评】吐槽《从你的全世界路过》
  16. windows如何把已安装的nodejs高版本降级为低版本node多环境
  17. excel一列求和_这么多超实用的excel技巧,花费6个小时整理出来的
  18. 张钹:中国人工智能奠基者
  19. java根据Freemarker模板渲染出Excel文件并在浏览器中下载
  20. 中南大学计算机学硕复试分数线,2021考研复试分数线已公布:中南大学

热门文章

  1. Java IO: 流
  2. 高级JAVA码农必须搞清楚它们的区别:instanceof、isInstance、isAssignableFrom
  3. Maven精选系列--私库搭建及使用
  4. 8张图带你轻松温习Java知识
  5. 如何给视频中插入视频,字幕,以及去掉前后广告
  6. 求素数为什么到平方根就行了
  7. 2017蓝桥杯省赛---java---B---7(日期问题)
  8. 双向链表的(CRUD)
  9. python获取当前进程id_从python进程名中获取进程id
  10. react antd confirm content list_React造轮系列:对话框组件 - Dialog 思路