zoukankan      html  css  js  c++  java
  • Java高级特性—锁

    1).synchronized
      加同步格式:
        synchronized( 需要一个任意的对象(锁) ){
          代码块中放操作共享数据的代码。
        }
      synchronized的缺陷
       synchronized是java中的一个关键字,也就是说是Java语言内置的特性。
         如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,
         等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
        1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
        2)线程执行发生异常,此时JVM会让线程自动释放锁。


    2).Lock
      lock和synchronized的区别
       1).Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
       2).Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,
        当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;
        而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
      3).java.util.concurrent.locks包下常用的类,lock是一个接口
      4).Lock接口中每个方法的使用:
        lock()、tryLock()、tryLock(long time, TimeUnit unit)、lockInterruptibly()是用来获取锁的。
        unLock()方法是用来释放锁的
      5).四个获取锁方法的区别:
        lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。

      由于在前面讲到如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,
      使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,
      防止死锁的发生。

      tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取
      失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。

       tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁
      时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间
      内拿到了锁,则返回true。

       lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能
      够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时
      ,假若此时线程A获取到了锁,而线程B只有等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的
      等待过程。

       注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。
       因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。
       而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。

      ReentrantLock
      直接使用lock接口的话,我们需要实现很多方法,不太方便,ReentrantLock是唯一实现了Lock接口的类,
      并且ReentrantLock提供了更多的方法,ReentrantLock,意思是“可重入锁”。

      一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个
      线程可以同时进行读操作。下面的ReentrantReadWriteLock实现了ReadWriteLock接口。

      ReentrantReadWriteLock
       ReentrantReadWriteLock里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和writeLock()用
      来获取读锁和写锁。

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


    3).Lock和synchronized的选择  
      1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
      2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,
    如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
      3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,
    不能够响应中断;
      4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
      5)Lock可以提高多个线程进行读操作的效率。
       在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),
    此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择

  • 相关阅读:
    fullCalendar改造计划之带农历节气节假日的万年历(转)
    Linked List Cycle
    Remove Nth Node From End of List
    Binary Tree Inorder Traversal
    Unique Binary Search Trees
    Binary Tree Level Order Traversal
    Binary Tree Level Order Traversal II
    Plus One
    Remove Duplicates from Sorted List
    Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/atomicbomb/p/9904242.html
Copyright © 2011-2022 走看看