Lock与synchronized 的区别

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

多次思考过这个问题,都没有形成理论,今天有时间了,我把他总结出来,希望对大家有所帮助

 

 

1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候

     线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,

     如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断

     如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

 

    ReentrantLock获取锁定与三种方式:
    a)  lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁

    b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;

    c)tryLock(long timeout,TimeUnit unit),   如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;

    d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

 

2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

 

3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

 

 

下面内容 是转载 http://zzhonghe.iteye.com/blog/826162

 

5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类。了解其性能的优劣程度,有助与我们在特定的情形下做出正确的选择。

总体的结论先摆出来: 

synchronized:
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

ReentrantLock:
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

Atomic:
和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。


所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。

先贴测试结果:再贴代码(Atomic测试代码不准确,一个同步中只能有1个Actomic,这里用了2个,但是这里的测试只看速度)
==========================
round:100000 thread:5
Sync = 35301694
Lock = 56255753
Atom = 43467535
==========================
round:200000 thread:10
Sync = 110514604
Lock = 204235455
Atom = 170535361
==========================
round:300000 thread:15
Sync = 253123791
Lock = 448577123
Atom = 362797227
==========================
round:400000 thread:20
Sync = 16562148262
Lock = 846454786
Atom = 667947183
==========================
round:500000 thread:25
Sync = 26932301731
Lock = 1273354016
Atom = 982564544

代码如下:

 

package test.thread;   import static java.lang.System.out;   import java.util.Random;   
import java.util.concurrent.BrokenBarrierException;   
import java.util.concurrent.CyclicBarrier;   
import java.util.concurrent.ExecutorService;   
import java.util.concurrent.Executors;   
import java.util.concurrent.atomic.AtomicInteger;   
import java.util.concurrent.atomic.AtomicLong;   
import java.util.concurrent.locks.ReentrantLock;   public class TestSyncMethods {   public static void test(int round,int threadNum,CyclicBarrier cyclicBarrier){   new SyncTest("Sync",round,threadNum,cyclicBarrier).testTime();   new LockTest("Lock",round,threadNum,cyclicBarrier).testTime();   new AtomicTest("Atom",round,threadNum,cyclicBarrier).testTime();   }   public static void main(String args[]){   for(int i=0;i<5;i++){   int round=100000*(i+1);   int threadNum=5*(i+1);   CyclicBarrier cb=new CyclicBarrier(threadNum*2+1);   out.println("==========================");   out.println("round:"+round+" thread:"+threadNum);   test(round,threadNum,cb);   }   }   
}   class SyncTest extends TestTemplate{   public SyncTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){   super( _id, _round, _threadNum, _cb);   }   @Override  /**  * synchronized关键字不在方法签名里面,所以不涉及重载问题  */  synchronized long  getValue() {   return super.countValue;   }   @Override  synchronized void  sumValue() {   super.countValue+=preInit[index++%round];   }   
}   class LockTest extends TestTemplate{   ReentrantLock lock=new ReentrantLock();   public LockTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){   super( _id, _round, _threadNum, _cb);   }   /**  * synchronized关键字不在方法签名里面,所以不涉及重载问题  */  @Override  long getValue() {   try{   lock.lock();   return super.countValue;   }finally{   lock.unlock();   }   }   @Override  void sumValue() {   try{   lock.lock();   super.countValue+=preInit[index++%round];   }finally{   lock.unlock();   }   }   
}   class AtomicTest extends TestTemplate{   public AtomicTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){   super( _id, _round, _threadNum, _cb);   }   @Override  /**  * synchronized关键字不在方法签名里面,所以不涉及重载问题  */  long  getValue() {   return super.countValueAtmoic.get();   }   @Override  void  sumValue() {   super.countValueAtmoic.addAndGet(super.preInit[indexAtomic.get()%round]);   }   
}   
abstract class TestTemplate{   private String id;   protected int round;   private int threadNum;   protected long countValue;   protected AtomicLong countValueAtmoic=new AtomicLong(0);   protected int[] preInit;   protected int index;   protected AtomicInteger indexAtomic=new AtomicInteger(0);   Random r=new Random(47);   //任务栅栏,同批任务,先到达wait的任务挂起,一直等到全部任务到达制定的wait地点后,才能全部唤醒,继续执行   private CyclicBarrier cb;   public TestTemplate(String _id,int _round,int _threadNum,CyclicBarrier _cb){   this.id=_id;   this.round=_round;   this.threadNum=_threadNum;   cb=_cb;   preInit=new int[round];   for(int i=0;i<preInit.length;i++){   preInit[i]=r.nextInt(100);   }   }   abstract void sumValue();   /*  * 对long的操作是非原子的,原子操作只针对32位  * long是64位,底层操作的时候分2个32位读写,因此不是线程安全  */  abstract long getValue();   public void testTime(){   ExecutorService se=Executors.newCachedThreadPool();   long start=System.nanoTime();   //同时开启2*ThreadNum个数的读写线程   for(int i=0;i<threadNum;i++){   se.execute(new Runnable(){   public void run() {   for(int i=0;i<round;i++){   sumValue();   }   //每个线程执行完同步方法后就等待   try {   cb.await();   } catch (InterruptedException e) {   // TODO Auto-generated catch block   e.printStackTrace();   } catch (BrokenBarrierException e) {   // TODO Auto-generated catch block   e.printStackTrace();   }   }   });   se.execute(new Runnable(){   public void run() {   getValue();   try {   //每个线程执行完同步方法后就等待   cb.await();   } catch (InterruptedException e) {   // TODO Auto-generated catch block   e.printStackTrace();   } catch (BrokenBarrierException e) {   // TODO Auto-generated catch block   e.printStackTrace();   }   }   });   }   try {   //当前统计线程也wait,所以CyclicBarrier的初始值是threadNum*2+1   cb.await();   } catch (InterruptedException e) {   // TODO Auto-generated catch block   e.printStackTrace();   } catch (BrokenBarrierException e) {   // TODO Auto-generated catch block   e.printStackTrace();   }   //所有线程执行完成之后,才会跑到这一步   long duration=System.nanoTime()-start;   out.println(id+" = "+duration);   }   }

 

转载于:https://my.oschina.net/91jason/blog/385059

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297921.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 内核 三天吐血,编译安装——吐血经验,内附脚本

程序包编译安装&#xff1a;源码包&#xff1a;name-VERSION-release.src.rpmrpm由源码包安装后&#xff0c;使用rpmbuild命令制作成二进制格式的rpm包&#xff0c;而后再安装源代码–> 预处理–> 编译(gcc)–> 汇编–> 链接–> 执行源代码组织格式&#xff1a;…

mac编辑器coda使用小贴条

前言&#xff1a;最近用mac开发环境了&#xff0c;自然一天到晚用coda&#xff0c;可总是有不顺的地方&#xff0c;搜到这篇文章感觉像看到了知音人&#xff0c;实在是解决了我不少疑难问题啊。外文针对的coda版本较低&#xff0c;我总结的针对版本是version1.7.3 coda快捷键操…

我在 GitHub 上发现了一款骚气满满的字体!

全世界只有3.14 % 的人关注了爆炸吧知识转自&#xff1a;量子位&#xff0c;作者&#xff1a;栗体这个字体叫 Leon Sans&#xff0c;表面看去平平无奇。但事实上&#xff0c;它并不是普通的字体&#xff0c;体内蕴藏着魔力。Leon Sans 最特别的地方在于&#xff0c;字体是由代码…

PHP 接收 UDP包_php只能做网站?基于swoole+websocket开发双向通信应用

前言众所周知&#xff0c;PHP用于开发基于HTTP协议的网站应用非常便捷。而HTTP协议是一种单向的通信协议&#xff0c;只能接收客户端的请求&#xff0c;然后响应请求&#xff0c;不能主动向客户端推送信息。因此&#xff0c;一些实时性要求比较高的应用&#xff0c;如实时聊天、…

WPF 实现火炬效果

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织欢迎转发、分享、点赞、在看&#xff0c;谢谢~。 01—效果预览02—代码如下一、FireControl.cs 代码如下using System; using System.Collections.Generic; using System.Linq; using System.Tex…

08 comet反向ajax

一&#xff1a;HTTP协议与技久链接分块传输---->反向ajax 反向ajax又叫comet, server push,服务器推技术. 应用范围: 网页聊天服务器,, 新浪微博在线聊天,google mail 网页聊天,都有用到. 原理: 一般而言, HTTP协议的特点, 连接<->断开. 具体什么时间断开? 服务器响应…

男朋友出的性格测试题

1 一家人出去玩了三天&#xff0c;把猫忘在家里了&#xff01;2 嗷呜3 竟然毫无违和感4 叫你一声造句鬼才不过分吧5 秋天原来是这样来的嘛~6 当代嗑cp网友现状5 现在的年轻人都哪里学来的这么多招数内容自沙雕男友的日常你点的每个赞&#xff0c;我都认真当成了喜欢

linux连接建立的时间,用timedatectl在Linux中检查当前时区及更改时区(创建符号链接来更改时区)...

本文介绍如何在Linux操作系统中设置或更改时区的方法&#xff0c;可以使用timedatectl&#xff0c;包括通过创建符号链接来更改时区。前言时区是具有相同标准时间的地理区域&#xff0c;通常&#xff0c;时区是在操作系统的安装过程中设置的&#xff0c;但以后可以轻松更改。对…

mapbox 导航_狂甩不掉,骑行最稳手机支架!一体式安装太方便,秒变单车导航仪...

发对于骑行爱好者而言&#xff0c;对手机支架的稳固性有很高的要求&#xff0c;同时支架体积不能太大&#xff0c;对手机本身也要有一定的保护性&#xff0c;手机安放好&#xff0c;骑行才能更自在&#xff01;一个舒适的手机支架&#xff0c;对于业务繁忙或者像小渣一样的路痴…

Docker小白到实战之Docker网络简单了解一下

前言现在对于Docker容器的隔离性都有所了解了&#xff0c;但对容器IP地址的分配、容器间的访问等还是有点小疑问&#xff0c;如果容器的IP由于新启动导致变动&#xff0c;那又怎么才能保证原有业务不会被影响&#xff0c;这就和网络有挂钩了&#xff0c;接下来就大概说说。正文…

^_^家园游记^_^

j 你梦想中的家是怎么家的呢&#xff1f; 是鲁宾逊漂流记中那样&#xff1a;一个荒岛&#xff0c;一片青山绿水的悠闲自在&#xff1f; 还是让人流连忘返的色彩斑斓&#xff0c;鳞次栉比&#xff0c;浓浓的欧式典雅&#xff1f; 或是奔放自由的乡村田园&#xff0c;精…

sigar如何获取linux的buffer内存,Linux 下使用Sigar 获取内存信息

上一篇文章介绍了linux下的sigar 库,并使用sigar 库来获取cpu 使用率,本文在这里介绍一下如何使用sigar 库获取内存信息.和cpu 一样,sigar中有和内存相关的结构体sigar_mem_t,我们来看一下结构体原型:typedef struct {sigar_uint64_tram,total,used,free,actual_used,actual_fr…

如何将手机投屏到电脑_手机如何投屏到电脑上?详细教程看这里,手机投屏

手机再大的屏幕&#xff0c;也没有手机投屏到电脑、电视的体验爽。那么哪款投屏软件好用&#xff1f;又如何使用呢&#xff1f;下面小编给大家介绍下金舟苹果手机投屏软件&#xff0c;一起来看看如何将手机投屏到电脑上&#xff0c;详细步骤如下。第一步、首先&#xff0c;在电…

inputstream是否一定要close_汽车加装行李架后,总被交警拦下,类似改装,是否一定要备案...

其实改装不是儿戏&#xff0c;有些部位是一定不能触碰的&#xff0c;汽车“轻改”后担心上路被交警处罚&#xff0c;哪些是不能触碰的“红杠杠”&#xff0c;汽车加装行李架后&#xff0c;总被交警拦下&#xff0c;类似改装&#xff0c;是否一定需要备案&#xff0c;是我们今天…

不好意思,爱因斯坦这次,又对了!

▲ 点击查看在科学界中&#xff0c;有一个非常著名的概念&#xff0c;叫做后设认知。官方解释是&#xff1a;人们是如何对自己的思维模式进行反思。打个简单的比方&#xff1a;你学习或者自己孩子学习的时候&#xff0c;会不会经常出现一道数学题反复做错的情况&#xff0c;明明…

开源Math.NET基础数学类库使用(04)C#解析Matrix Marke数据格式

原文:【原创】开源Math.NET基础数学类库使用(04)C#解析Matrix Marke数据格式开源Math.NET基础数学类库使用系列文章总目录&#xff1a; 1.开源.NET基础数学计算组件Math.NET(一)综合介绍 2.开源.NET基础数学计算组件Math.NET(二)矩阵向量计算 3.开源.NET基础数学计算组件Ma…

元胞自动机模型_【ABM仿真模拟】第三章 元胞自动机 B

是新朋友吗&#xff1f;记得先点蓝字关注我哦&#xff5e;第三章 元胞自动机 B2020/01/233.3投票模型(Voting) 课程导读无论是国内国外&#xff0c;投票结果的预测都异常受到关注。在众多唐斯模型、中间选民模型 、以及Sznajd模型中&#xff0c;投票模型作为典型的元胞自动机&a…

喜报!985大学首次登上Nature封面,这所学校可太不容易了!

全世界只有3.14 % 的人关注了爆炸吧知识建校64年来&#xff0c;第一次登上期刊封面又一所985院校出息了&#xff01;伦敦时间6月4号&#xff0c;《Nature》刊发了电子科技大学邓旭教授团队的最新研究成果&#xff0c;并被选为当期封面。《设计坚固的超疏水表面》《Nature》作为…

getbean方法找不到bean_iphone手机静音找不到怎么办 iphone静音找不到解决方法【图文】...

一个网友给小编留言&#xff0c;询问&#xff1a;“我的iphone调静音了现在找不到&#xff0c;有什么工具能找到”这一个问题&#xff0c;因此&#xff0c;在今天的iPhone使用教程&#xff0c;小编就给大家讲解一下具体的解决方法&#xff0c;那么&#xff0c;iphone手机静音找…

成长 | 《大厂晋升指南》学习总结(上)

【学习总结】| Edison Zhou温馨提示&#xff1a;文中的贴图均来自极客时间《大厂晋升指南》课程。0写在开头今年加入了一家产业互联网平台企业&#xff0c;公司刚好也开始借鉴阿里的职级体系。对于从来没有在互联网企业呆过的我&#xff0c;对于职级体系还比较陌生&#xff0c;…