Synchronize和ReentrantLock区别
2019独角兽企业重金招聘Python工程师标准>>>
目录介绍
- 1.Synchronize和ReentrantLock区别
- 1.1 相似点
- 1.2 区别
- 1.3 什么是线程安全问题?如何理解
- 1.4 线程安全需要保证几个基本特性
- 2.Synchronize在编译时如何实现锁机制
- 3.ReentrantLock使用方法
- 4.ReentrantLock锁机制测试案例分析
- 4.1 代码案例分析
- 4.2 什么时候选择用ReentrantLock
- 4.3 公平锁和非公平锁有何区别
- 5.问答测试题
- 5.1 ReentrantLock和synchronized使用分析
好消息
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
- 链接地址:https://github.com/yangchong211/YCBlogs
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
关于锁机制文章
- 01.Synchronize深入解析
- Synchronize深入解析,sychonized method 和 synchonized代码块的效率问题
- 02.Synchronize和ReentrantLock区别
- Synchronize和ReentrantLock区别,Synchronize在编译时如何实现锁机制,ReentrantLock锁机制测试案例分析,公平锁和非公平锁有何区别等等
- 03.死锁的发生,定位与修复
- 死锁的概念和产生死锁的根本原因是什么?死锁的预防策略中资源有序分配策略是什么。死锁发生的场景,死锁的危害,出现死锁需要满足条件分析,如何预防死锁,如何定位死锁,以及死锁修复方案分析等等
1.Synchronize和ReentrantLock区别
1.1 相似点:
- 这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。
1.2 区别:
1.2.1 API层面
- 这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。
- synchronized既可以修饰方法,也可以修饰代码块。
//synchronized修饰一个方法时,这个方法叫同步方法。 public synchronized void test() { //方法体``}synchronized(Object) { //括号中表示需要锁的对象. //线程执行的时候会对Object上锁 }
- ReentrantLock使用
private ReentrantLock lock = new ReentrantLock(); public void run() {lock.lock();try{for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}finally{lock.unlock();} }
1.2.2 等待可中断
- 等待可中断是指当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。可等待特性对处理执行时间非常长的同步快很有帮助。
- 具体来说,假如业务代码中有两个线程,Thread1 Thread2。假设 Thread1 获取了对象object的锁,Thread2将等待Thread1释放object的锁。
- 使用synchronized。如果Thread1不释放,Thread2将一直等待,不能被中断。synchronized也可以说是Java提供的原子性内置锁机制。内部锁扮演了互斥锁(mutual exclusion lock ,mutex)的角色,一个线程引用锁的时候,别的线程阻塞等待。
- 使用ReentrantLock。如果Thread1不释放,Thread2等待了很长时间以后,可以中断等待,转而去做别的事情。
1.2.3 公平锁
- 公平锁是指多个线程在等待同一个锁时,必须按照申请的时间顺序来依次获得锁;而非公平锁则不能保证这一点。非公平锁在锁被释放时,任何一个等待锁的线程都有机会获得锁。
- synchronized的锁是非公平锁,ReentrantLock默认情况下也是非公平锁,但可以通过带布尔值的构造函数要求使用公平锁。
- ReentrantLock 构造器的一个参数是boolean值,它允许您选择想要一个公平(fair)锁,还是一个不公平(unfair)锁。公平锁:使线程按照请求锁的顺序依次获得锁, 但是有成本;不公平锁:则允许讨价还价
- 那么如何用代码设置公平锁呢?如下所示
1.2.4 锁绑定多个条件
- ReentrantLock可以同时绑定多个Condition对象,只需多次调用newCondition方法即可。
- synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件。但如果要和多于一个的条件关联的时候,就不得不额外添加一个锁。
1.3 什么是线程安全问题?如何理解
- 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的,或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题 。
1.4 线程安全需要保证几个基本特性
- 1、原子性,简单说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现。
- 2、可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile 就是负责保证可见性的。
- 3、有序性,是保证线程内串行语义,避免指令重排等。
2.Synchronize在编译时如何实现锁机制
- Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。
3.ReentrantLock使用方法
- ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
- 1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。
- 2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。
- 3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。
- 使用方法代码如下
private ReentrantLock lock = new ReentrantLock(); public void run() {lock.lock();try{for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}finally{lock.unlock();} }
- 注意问题:为保证锁释放,每一个 lock() 动作,建议都立即对应一都立即对应一个 try-catch-finally
4.ReentrantLock锁机制测试案例分析
4.1 代码案例分析
- 代码如下所示
private void test2() {Runnable t1 = new MyThread();new Thread(t1,"t1").start();new Thread(t1,"t2").start(); }class MyThread implements Runnable {private ReentrantLock lock = new ReentrantLock();public void run() {lock.lock();try{for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}finally{lock.unlock();}} }//打印值如下所示 10-17 17:06:59.222 6531-6846/com.yc.cn.ycbaseadapter I/System.out: t1:0 10-17 17:06:59.222 6531-6846/com.yc.cn.ycbaseadapter I/System.out: t1:1 10-17 17:06:59.222 6531-6846/com.yc.cn.ycbaseadapter I/System.out: t1:2 10-17 17:06:59.222 6531-6846/com.yc.cn.ycbaseadapter I/System.out: t1:3 10-17 17:06:59.222 6531-6846/com.yc.cn.ycbaseadapter I/System.out: t1:4 10-17 17:06:59.224 6531-6847/com.yc.cn.ycbaseadapter I/System.out: t2:0 10-17 17:06:59.225 6531-6847/com.yc.cn.ycbaseadapter I/System.out: t2:1 10-17 17:06:59.225 6531-6847/com.yc.cn.ycbaseadapter I/System.out: t2:2 10-17 17:06:59.225 6531-6847/com.yc.cn.ycbaseadapter I/System.out: t2:3 10-17 17:06:59.225 6531-6847/com.yc.cn.ycbaseadapter I/System.out: t2:4
4.2 什么时候选择用ReentrantLock
- 适用场景:时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票
- 在确实需要一些 synchronized所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。 ReentrantLock 还具有可伸缩性的好处,应当在高度争用的情况下使用它,但是请记住,大多数 synchronized 块几乎从来没有出现过争用,所以可以把高度争用放在一边。我建议用 synchronized 开发,直到确实证明 synchronized 不合适,而不要仅仅是假设如果使用 ReentrantLock “性能会更好”。请记住,这些是供高级用户使用的高级工具。(而且,真正的高级用户喜欢选择能够找到的最简单工具,直到他们认为简单的工具不适用为止。)。一如既往,首先要把事情做好,然后再考虑是不是有必要做得更快。
- 使用场景代码展示【摘自ThreadPoolExecutor类,这个类中很多地方用到了这个锁。自己可以查看】:
/*** Rolls back the worker thread creation.* - removes worker from workers, if present* - decrements worker count* - rechecks for termination, in case the existence of this* worker was holding up termination*/ private void addWorkerFailed(Worker w) {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {if (w != null)workers.remove(w);decrementWorkerCount();tryTerminate();} finally {mainLock.unlock();} }
4.3 公平锁和非公平锁有何区别
- 公平性是指在竞争场景中,当公平性为真时,会倾向于将锁赋予等待时间最久的线程。公平性是减少线程“饥饿”(个别线程长期等待锁,但始终无法获取)情况发生的一个办法。
- 1、公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。
- 2、非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。
- 看下面代码案例所示:可以得出结论,公平锁指的是哪个线程先运行,那就可以先得到锁。非公平锁是不管线程是否是先运行,新的线程都有可能抢占已经在排队的线程的锁。
private void test3() {Service service = new Service();ThreadClass tcArray[] = new ThreadClass[10];for(int i=0;i<10;i++){tcArray[i] = new ThreadClass(service);tcArray[i].start();} }public class Service {ReentrantLock lock = new ReentrantLock(true);Service() {}void getThreadName() {System.out.println(Thread.currentThread().getName() + " 已经被锁定");} } public class ThreadClass extends Thread{private Service service;ThreadClass(Service service) {this.service = service;}public void run(){System.out.println(Thread.currentThread().getName() + " 抢到了锁");service.lock.lock();service.getThreadName();service.lock.unlock();} } //当ReentrantLock设置true,也就是公平锁时 10-17 19:32:22.422 6459-6523/com.yc.cn.ycbaseadapter I/System.out: Thread-5 抢到了锁 10-17 19:32:22.422 6459-6523/com.yc.cn.ycbaseadapter I/System.out: Thread-5 已经被锁定 10-17 19:32:22.424 6459-6524/com.yc.cn.ycbaseadapter I/System.out: Thread-6 抢到了锁 10-17 19:32:22.424 6459-6524/com.yc.cn.ycbaseadapter I/System.out: Thread-6 已经被锁定 10-17 19:32:22.427 6459-6525/com.yc.cn.ycbaseadapter I/System.out: Thread-7 抢到了锁 10-17 19:32:22.427 6459-6526/com.yc.cn.ycbaseadapter I/System.out: Thread-8 抢到了锁 10-17 19:32:22.427 6459-6525/com.yc.cn.ycbaseadapter I/System.out: Thread-7 已经被锁定 10-17 19:32:22.427 6459-6526/com.yc.cn.ycbaseadapter I/System.out: Thread-8 已经被锁定 10-17 19:32:22.427 6459-6527/com.yc.cn.ycbaseadapter I/System.out: Thread-9 抢到了锁 10-17 19:32:22.427 6459-6527/com.yc.cn.ycbaseadapter I/System.out: Thread-9 已经被锁定 10-17 19:32:22.428 6459-6528/com.yc.cn.ycbaseadapter I/System.out: Thread-10 抢到了锁 10-17 19:32:22.428 6459-6528/com.yc.cn.ycbaseadapter I/System.out: Thread-10 已经被锁定 10-17 19:32:22.429 6459-6529/com.yc.cn.ycbaseadapter I/System.out: Thread-11 抢到了锁 10-17 19:32:22.429 6459-6529/com.yc.cn.ycbaseadapter I/System.out: Thread-11 已经被锁定 10-17 19:32:22.430 6459-6530/com.yc.cn.ycbaseadapter I/System.out: Thread-12 抢到了锁 10-17 19:32:22.430 6459-6530/com.yc.cn.ycbaseadapter I/System.out: Thread-12 已经被锁定 10-17 19:32:22.431 6459-6532/com.yc.cn.ycbaseadapter I/System.out: Thread-14 抢到了锁 10-17 19:32:22.431 6459-6532/com.yc.cn.ycbaseadapter I/System.out: Thread-14 已经被锁定 10-17 19:32:22.432 6459-6531/com.yc.cn.ycbaseadapter I/System.out: Thread-13 抢到了锁 10-17 19:32:22.433 6459-6531/com.yc.cn.ycbaseadapter I/System.out: Thread-13 已经被锁定//当ReentrantLock设置false,也就是非公平锁时 10-17 19:34:58.102 7089-7183/com.yc.cn.ycbaseadapter I/System.out: Thread-5 抢到了锁 10-17 19:34:58.102 7089-7184/com.yc.cn.ycbaseadapter I/System.out: Thread-6 抢到了锁 10-17 19:34:58.103 7089-7183/com.yc.cn.ycbaseadapter I/System.out: Thread-5 已经被锁定 10-17 19:34:58.103 7089-7185/com.yc.cn.ycbaseadapter I/System.out: Thread-7 抢到了锁 10-17 19:34:58.103 7089-7185/com.yc.cn.ycbaseadapter I/System.out: Thread-7 已经被锁定 10-17 19:34:58.103 7089-7184/com.yc.cn.ycbaseadapter I/System.out: Thread-6 已经被锁定 10-17 19:34:58.104 7089-7186/com.yc.cn.ycbaseadapter I/System.out: Thread-8 抢到了锁 10-17 19:34:58.105 7089-7186/com.yc.cn.ycbaseadapter I/System.out: Thread-8 已经被锁定 10-17 19:34:58.108 7089-7187/com.yc.cn.ycbaseadapter I/System.out: Thread-9 抢到了锁 10-17 19:34:58.108 7089-7187/com.yc.cn.ycbaseadapter I/System.out: Thread-9 已经被锁定 10-17 19:34:58.111 7089-7188/com.yc.cn.ycbaseadapter I/System.out: Thread-10 抢到了锁 10-17 19:34:58.112 7089-7188/com.yc.cn.ycbaseadapter I/System.out: Thread-10 已经被锁定 10-17 19:34:58.112 7089-7189/com.yc.cn.ycbaseadapter I/System.out: Thread-11 抢到了锁 10-17 19:34:58.113 7089-7189/com.yc.cn.ycbaseadapter I/System.out: Thread-11 已经被锁定 10-17 19:34:58.113 7089-7193/com.yc.cn.ycbaseadapter I/System.out: Thread-14 抢到了锁 10-17 19:34:58.113 7089-7193/com.yc.cn.ycbaseadapter I/System.out: Thread-14 已经被锁定 10-17 19:34:58.115 7089-7190/com.yc.cn.ycbaseadapter I/System.out: Thread-12 抢到了锁 10-17 19:34:58.115 7089-7190/com.yc.cn.ycbaseadapter I/System.out: Thread-12 已经被锁定 10-17 19:34:58.116 7089-7191/com.yc.cn.ycbaseadapter I/System.out: Thread-13 抢到了锁 10-17 19:34:58.116 7089-7191/com.yc.cn.ycbaseadapter I/System.out: Thread-13 已经被锁定
5.问答测试题
5.1 ReentrantLock和synchronized使用分析
- ReentrantLock是Lock的实现类,是一个互斥的同步器,在多线程高竞争条件下,ReentrantLock比synchronized有更加优异的性能表现。
- 1 用法比较
- Lock使用起来比较灵活,但是必须有释放锁的配合动作
- Lock必须手动获取与释放锁,而synchronized不需要手动释放和开启锁
- Lock只适用于代码块锁,而synchronized可用于修饰方法、代码块等
- 2 特性比较
- ReentrantLock的优势体现在:
- 具备尝试非阻塞地获取锁的特性:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
- 能被中断地获取锁的特性:与synchronized不同,获取到锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放
- 超时获取锁的特性:在指定的时间范围内获取锁;如果截止时间到了仍然无法获取锁,则返回
- ReentrantLock的优势体现在:
- 3 注意事项
- 在使用ReentrantLock类的时,一定要注意三点:
- 在finally中释放锁,目的是保证在获取锁之后,最终能够被释放
- 不要将获取锁的过程写在try块内,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故被释放。
- ReentrantLock提供了一个newCondition的方法,以便用户在同一锁的情况下可以根据不同的情况执行等待或唤醒的动作。
- 在使用ReentrantLock类的时,一定要注意三点:
关于其他内容介绍
01.关于博客汇总链接
- 1.技术博客汇总
- 2.开源项目汇总
- 3.生活博客汇总
- 4.喜马拉雅音频汇总
- 5.其他汇总
02.关于我的博客
- 我的个人站点:www.yczbj.org,www.ycbjie.cn
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
- 简书:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
- 开源中国:https://my.oschina.net/zbj1618/blog
- 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 邮箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
转载于:https://my.oschina.net/zbj1618/blog/2249042
Synchronize和ReentrantLock区别相关推荐
- synchronized和ReentrantLock区别
1.区别: 1)Lock是一个接口,synchronized是Java中的关键字,synchronized是内置的语言实现: 2)synchronized发生异常时,会自动释放线程占用的锁,故不会发生 ...
- synchronized和ReentrantLock区别浅析 (转载地址:http://blog.csdn.net/zmx729618/article/details/51594166)
一.什么是sychronized sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类. 在修饰代码块的时候需要一个reference对象作为锁的对象. 在修饰方法的时候默 ...
- synchronized和ReentrantLock区别,用新的lock有什么好处?举例说说
原始构成:synchronized是JVM层面的,底层通过monitorenter和monitorexit来实现的.Lock是JDK API层面的.(synchronized一个enter会有两个ex ...
- python的锁机制_python锁机制
python 多线程 真正的多线程吗? 对于多核处理器,在同一时间确实可以多个线程独立运行,但在Python中确不是这样的了.原因在于,python虚拟机中引入了GIL这一概念.GIL(Global ...
- 滴滴java开发面试题_滴滴java开发工程师面试问题解答(第一回)
有位同学写了一个滴滴面试拿offer的经历,据说还面了滴滴的CTO,我就好奇,这CTO面又能是个啥水平呢?对他在文章中提到的部分问题做个解答吧. 原文请见滴滴CTO五轮面试真是太刺激了,Java高级工 ...
- reentrantlock原理_分享:synchronized和ReentrantLock的实现原理知识点
前言 通常呢,会在并发情况下,同时操作某一业务从而造成数据重复提交,业务混乱等问题,通常呢,遇到解决类似问题可采用加锁,限流等问题来解决,那么看看这篇关于java中关于锁中synchronized和R ...
- JavaSe8中的各种区别(持续更新中)
1.简述自动装箱和拆箱 基本数据类型转换为包装类的过程称为装箱,例如把 int 包装成 Integer 类的对象:包装类变为基本数据类型的过程称为拆箱,例如把 Integer 类的对象重新简化为 in ...
- Nginx面试!mysql时间类型以及获取当前时间,干货满满
一面:70分钟 突击电话面试 正思考着项目功能模块,阿里面试官打来了电话,开始了阿里一面. 阿里面试官自我介绍,介绍了5分钟左右,部门的情况,主要的业务 提问开始 会哪些操作系统 Linux会一点 说 ...
- 厉害了!java多线程导出excel
一.前言 红黑树,是一种高效的自平衡二叉查找树 Rudolf Bayer 于1978年发明红黑树,在当时被称为对称二叉 B 树(symmetric binary B-trees).后来,在1978年被 ...
最新文章
- hdu 2085 核反应堆
- 经典论文复现 | InfoGAN:一种无监督生成方法
- canvas做的图片查看器1
- java 第十一章总结
- Linux快速搭建FTP服务器
- Zabbix监控内存
- 设置返回IOS开发(26)之UITableView的页眉和页脚
- 检测手机屏幕是否亮屏解锁
- 更改ESXi主机root用户密码
- Python爬取淘宝商品类目
- sql升级重启计算机失败win10,win10纯净版安装sql server 2008重启失败的解决办法
- Linux下 Yum 是什么
- field ii:一些查看技巧
- 央视新闻同款 教你1分钟做出三维地球动画特效
- 初入职场,为人处事(社牛勿看)
- win10 设置为静态ip地址
- 微信小程序cameraContext拍摄的视频或照片上传后端,不需要处理实时监听的ArrayBuffer格式的视频数据,只需要直接使用wx.uploadFile上传后端,简单好用(带前后端代码)
- Java小农养成记第二十一天
- 图像处理之opencv保存视频图片
- 真知识,也会成为毒药
热门文章
- deepnode处理过的图片_教你用PS快速修复图片脏乱和瑕疵,快来一起学习吧!
- Jshop小程序商城,小程序端。后台采用Thinkphp5.1框架开发
- PHP双码率视频云转码服务网站源码 支持M3u8秒切
- 百度SEO站群爱叶解析接口php网站源码
- java 初始化 静态变量,关于spring:Java初始化静态变量的时间顺序
- WordPress美化_节日灯笼插件
- 临时停车码-扫码拨号发信息HTML源码
- 2011年白银机会远超黄金 四妙招帮您赚大
- Google 的PageRank值对网站成功有多重要
- php获得可靠的精准的当前时间 ( 通过授时服务器 )