zoukankan      html  css  js  c++  java
  • ReentrantLock和synchronized两种锁定机制

    ReentrantLock和synchronized两种锁定机制

    1.应用synchronized同步锁

    把代码块声明为 synchronized,使得该代码具有 原子性(atomicity)和 可见性(visibility)。
    原子性意味着一个线程一次只能执行由一个指定监控对象(lock)保护的代码,从而防止多个线程在更新共享状态时相互冲突。
    可见性类似volatile关键字。

    2.应用ReentrantLock显示锁

    ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上)。

    可重入锁 ReentrantLock 的含义是当某个线程获取某个锁后,在未释放锁的情况下,第二次再访问该锁锁定的另一代码块时,可以重新进入该块。

    ReentrantLock典型的使用方法:

    class X {
       private final ReentrantLock lock = new ReentrantLock();
       // ...
    
       public void m() { 
         lock.lock();  // block until condition holds
         try {
           // ... method body
         } finally {
           lock.unlock();
         }
       }
     }
    

      

    (1)什么情况下可以使用 ReentrantLock
    使用synchronized 的一些限制:
    无法中断正在等候获取一个锁的线程;
    无法通过投票得到一个锁;
    释放锁的操作只能与获得锁所在的代码块中进行,无法在别的代码块中释放锁;
    ReentrantLock 没有以上的这些限制,且必须是手工释放锁。

    (2)简单对比
    主要相同点:Lock能完成synchronized所实现的所有功能
    主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,当许多线程都在争用同一个锁时,使用 ReentrantLock 的总体开支通常要比 synchronized 少得多。
    synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。

    3.对synchronized(this)的理解 

    一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线
    程必须等待当前线程执行完这个代码块以后才能执行该代码块。
    二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized
    (this)同步代码块。
    三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)
    同步代码块的访问将被阻塞。
    四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个
    object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
    五、以上规则对其它对象锁同样适用

    4.Synchronize 和 Lock 有什么不同

    (1)用法区别
    synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
    lock(显示锁):需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对 象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
    (2)synchronized和lock性能区别
    synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。
    synchronized采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。
    Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就 是CAS操作(Compare and Swap)。

    (3)synchronized和lock用途区别
    synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
    1.某个线程在等待一个锁的控制权的这段时间需要中断
    2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
    3.具有公平锁功能,每个到来的线程都将排队等候、

    5.关于两种机制的精彩评论

    如果我们把每个线程理解成 一个个门,门都需要上锁,
    在没有ReentrantLock之前,我们上锁,可能统一用sycnchronized(钥匙),大家都在竞争锁钥匙,钥匙只有一把,谁先拥有谁就先开门进去,门打不开的就一直卡死等待,浪费时间,还不能干其他事情,就消耗在这里了

    有了ReentrantLock,英文解释可重用锁, 就不需要钥匙了,我们可以灵活的为一组门(thread)配置一把特殊的锁,为另一组门配置另外一把锁,多灵活啊,这把锁仍然拥有synchronized的功能,
    1.如果用tryLock(非阻塞),此次获取不到锁,那你也不会等待,可以在门口玩会手机,或者去超时买菜,一会再来trylock一次 这个方法更灵活;
    2.如果用lock(阻塞),那就跟synchronized一样的,获取了锁,就开门了,同一时刻 其他的门就死等,不能干其他事情;

  • 相关阅读:
    【ElasticSearch】异常错误
    【CentOS7】系统设置
    【Ubuntu 18.04.03_64】系统配置
    【MySql】语法学习
    【ElasticSearch】聚合使用学习
    【Spring Boot】Spring Security登陆异常出路
    【ElasticSearch】查询使用学习
    Spring boot X-Frame-Options 异常 a frame because it set 'X-Frame-Options' to 'deny'
    【Thymeleaf】使用学习
    【MySql】日期时间
  • 原文地址:https://www.cnblogs.com/binyue/p/4480904.html
Copyright © 2011-2022 走看看