>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 21782 个阅读者 刷新本主题
 * 贴子主题:  Synchronized与ReentrantLock区别总结 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-02-07 00:03:07     消息  查看  搜索  好友  邮件  复制  引用

   这篇文章是关于这两个同步锁的简单总结比较,关于底层源码实现原理没有过多涉及,后面会有关于这两个同步锁的底层原理篇幅去介绍。    

相似点:

     这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。    

功能区别:

     这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成

     便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

    锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized    

性能的区别:

     在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。    

1.Synchronized

     Synchronized进过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。        

  1.       public   class  SynDemo{
  2.        public  static  void  main (String[] arg){
  3.      Runnable t1= new MyThread();
  4.      new Thread(t1, "t1").start();
  5.      new Thread(t1, "t2").start();
  6.      }
  7.      }
  8.        class  MyThread  implements  Runnable {
  9.      @Override
  10.        public  void  run () {
  11.      synchronized ( this) {
  12.      for( int i= 0;i< 10;i++)
  13.      System.out.println(Thread.currentThread().getName()+ ":"+i);
  14.      }
  15.      }
  16.      }

2.ReentrantLock

     由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

     1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。

     2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

     公平锁、非公平锁的创建方式:    

  1.       //创建一个非公平锁,默认是非公平锁
  2.      Lock lock =  new ReentrantLock();
  3.      Lock lock =  new ReentrantLock( false);
  4.       //创建一个公平锁,构造传参true
  5.      Lock lock =  new ReentrantLock( true);

      3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么 随机唤醒一个线程要么唤醒全部线程。    

ReenTrantLock实现的原理:

     之后还会总结一篇ReenTrantLock相关的原理底层原理分析,简单来说 ,ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。    

什么情况下使用ReenTrantLock:

     答案是,如果你需要实现ReenTrantLock的三个独有功能时。

      ReentrantLock的用法如下:        

  1.       public   class  SynDemo{
  2.        public  static  void  main (String[] arg){
  3.      Runnable t1= new MyThread();
  4.      new Thread(t1, "t1").start();
  5.      new Thread(t1, "t2").start();
  6.      }
  7.      }
  8.        class  MyThread  implements  Runnable {
  9.      private Lock lock= new ReentrantLock();
  10.        public  void  run () {
  11.      lock.lock();
  12.      try{
  13.      for( int i= 0;i< 5;i++)
  14.      System.out.println(Thread.currentThread().getName()+ ":"+i);
  15.      } finally{
  16.      lock.unlock();
  17.      }
  18.      }
  19.      }

       对ReentrantLock的源码分析这有一篇很好的文章

     http://www.blogjava.net/zhanglongsr/articles/356782.html

                                                
----------------------------
原文链接:https://blog.csdn.net/zxd8080666/article/details/83214089

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-02-07 00:03:07 重新编辑]
  Java面向对象编程-->Swing组件(下)
  JavaWeb开发-->使用Session(Ⅰ)
  JSP与Hibernate开发-->使用JPA和注解
  Java网络编程-->Java反射机制
  精通Spring-->通过Vuex进行状态管理
  Vue3开发-->创建综合购物网站应用
  java实现动态编译并动态加载
  孙卫琴的视频课程的源代码下载
  面试官:NIO的优化实现原理了解吗?图文结合教你如何正确避坑
  Java设计模式: 单一职责原则和依赖倒置原则详解
  Java 语言中十大“坑爹”功能!
  用注解去代替if-else的技巧
  使用 RocketMQ 事务消息,实现分布事务
  Eclipse的安装配置
  Java注解的定义和使用
  如何优雅地打印一个Java对象?
  Eclipse使用指南:常用视图(View) 的用法
  Java入门实用代码:获取远程文件大小
  Java入门实用代码:打印九九乘法表
  史上最全正则表达式合集(马上收藏)
  判断一个字符是否是汉字
  更多...
 IPIP: 已设置保密
树形列表:   
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。