zoukankan      html  css  js  c++  java
  • 关于synchronize与lock的区别

    参考文献:https://www.cnblogs.com/cloudblogs/p/6440160.html

    一、synchronize修饰不同代码都是锁住了什么?
    大家都知道synchronize可以修饰属性、代码块,方法、类,但是修饰不同的代码锁住的内容是不同的。
    1、修饰非静态属性和方法时,拿到的是调用这个方法或者属性的对象(this)的锁
    2、synchronize()修饰代码块时,拿到的是指定对象的锁
    3、修饰类、静态方法、静态代码块时,由于没有this指针,因此拿到的是类锁,也就是该类的class对象
    !!!注意:一个对象只有一个锁
     
    二、关于synchronize
    由于synchronize是由JVM实现的,因此当加锁代码出现异常时,对象锁可以由JVM释放,包含以下三种情况:
    1、 占有锁的线程执行完了代码块,然后释放对锁的占有;
    2、 占有锁的线程发生了异常,此时JVM会让线程自动释放锁;
    3、 占有锁的线程调用了wait()方法,从而进入了WAITING状态需要释放锁。
     
    三、关于Lock

     由于Lock是由JDK实现的,所以不像synchronize锁的获取和释放都是由JVM控制的,Lock的获取和释放都需要手动进行,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生

    1、lock() 获取锁与释放锁 ,如果锁已被其他线程获取,则进行等待。

    1 Lock lock = ...; lock.lock();
    2 try{    
    3    //处理任务
    4 }catch(Exception ex){
    5 }finally{
    6      lock.unlock();   //释放锁 
    7 }

    2、tryLock() 获取锁时有返回值可以得知获取锁操作是否成功 

     1 Lock lock = ...; 
     2 if(lock.tryLock()) {
     3       try{ 
     4          //处理任务     
     5    }catch(Exception ex){
     6      }finally{
     7           lock.unlock();   //释放锁      
     8   }  
     9 }else {   
    10   //如果不能获取锁,则直接做其他事情 
    11 }

    如果获取成功则返回True,如果锁被其他线程占用则返回FALSE,该方法会立即返回结果不会让线程一直处于等待状态

    3、tryLock(long time,TimeUnit unit) 与tryLock() 类似,但是与tryLock立即返回结果不同,该方法在拿不到锁的情况下回等待time时间,如果在限定时间内还是拿不到锁就返回FALSE,如果在一开始或者等待时间内拿到锁则返回TRUE。

    4、lockInterruptibly() 

    通过这个方法尝试获取锁时,如果线程正在等待获取锁,则该线程可以响应Thread.interrupt()中断。synchronize对于没有获得锁处于等待状态的线程无法响应中断。

    1 public void method() throws InterruptedException {     
    2     lock.lockInterruptibly();    
    3     try {        //.....     }     
    4     finally { lock.unlock(); }   
    5 }

    lockInterruptibly方法必须放在try块中或者在调用lockInterruptibly的方法外声明抛出InterruptedException,推荐使用后者。

    5、readWriteLock()

    该锁提升了读操作的效率,不过要注意的是,如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程也会一直等待释放写锁。

    四、Lock和synchronized的选择:
    1、 Lock是一个接口,属于JDK层面的实现;而synchronized属于Java语言的特性,其实现有JVM来控制(代码执行完毕,出现异常,wait时JVM会主动释放锁)。
    2、 synchronized在发生异常时,会自动释放掉锁,故不会发生死锁现(此时的死锁一般是代码逻辑引起的);而Lock必须在finally中主动unlock锁,否则就会出现死锁。
    3、 Lock能够响应中断,让等待状态的线程停止等待;而synchronized不行。
    4、 通过Lock可以知道线程是否成功获得了锁,而synchronized不行。
    5、 Lock提高了多线程下对读操作的效率。
     
    五、扩展
    1、可重入锁:synchronized和ReentrantLock都是可重入锁。当一个线程执行到某个synchronized方法时,比如说method1,而在method1中会调用另外一个synchronized方法method2,此时线程不必重新去申请锁,而是可以直接执行方法method2。
     
    2、可中断锁:等待获得锁的等待过程是否可以中断。通过上面的例子,我们可以得知Lock是可中断锁,而synchronized不是。
     
    3、公平锁:尽量以请求的顺序来获取锁,同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该锁。synchronized是非公平锁,而ReentrantLock和ReentReadWriteLock默认情况下是非公平锁,但是可以设置成公平锁。
    ReentrantLock lock = new ReentrantLock(true);
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
    设置为TRUE即为公平锁,为FALSE或者无参数为非公平锁。
     
    4、读写锁:读写锁将对临界资源的访问分成了两个锁,一个读锁和一个写锁。增加读写灵活性。即ReadWriteLock接口及其实现ReentrantReadWriteLock。
  • 相关阅读:
    BZOJ2843:极地旅行社(LCT入门题)
    BZOJ2049:Cave 洞穴勘测 (LCT入门)
    【LSGDOJ1383】修改回文 dp
    【NOIP2016】愤怒的小鸟
    【USACO11NOV】牛的阵容Cow Lineup 尺取法+哈希
    【LSGDOJ1836】: 量化交易 贪心
    【网络流24题】魔术球问题 二分答案+最小路径覆盖
    【网络流24题】1745: 餐巾计划问题
    【网络流24题】分配问题 最小最大费用最大流
    【LSGDOJ1834 Tree】树链剖分
  • 原文地址:https://www.cnblogs.com/simpleDi/p/11517552.html
Copyright © 2011-2022 走看看