可重入锁和不可重入锁

锁的简单应用html


用lock来保证原子性(this.count++这段代码称为临界区)java

什么是原子性,就是不可分,从头执行到尾,不能被其余线程同时执行。数组

可经过CAS来实现原子操做this

CAS(Compare and Swap):spa

CAS操做须要输入两个数值,一个旧值(指望操做前的值)和一个新值,在操做期间先比较下旧值有没有发生变化,若是没有发生变化,才交换成新值,发生了变化则不交换。操作系统

CAS主要经过compareAndSwapXXX()方法来实现,而这个方法的实现须要涉及底层的unsafe类.net

unsafe类:java不能直接访问操做系统底层,而是经过本地方法来访问。Unsafe类提供了硬件级别的原子操做线程

这里有个介绍原子操做的博客设计

https://my.oschina.net/xinxingegeya/blog/499223code

还有对unsafe类详解的博客

http://www.cnblogs.com/mickole/articles/3757278.html

 

 1 public class Counter{
 2     private Lock lock = new Lock();
 3     private int count = 0;
 4     public int inc(){
 5         lock.lock();
 6         this.count++;
 7         lock.unlock();
 8         return count;
 9     }
10 }

不可重入锁


先来设计一种锁

 1 public class Lock{
 2     private boolean isLocked = false;
 3     public synchronized void lock() throws InterruptedException{
 4         while(isLocked){    
 5             wait();
 6         }
 7         isLocked = true;
 8     }
 9     public synchronized void unlock(){
10         isLocked = false;
11         notify();
12     }
13 }

这实际上是个不可重入锁,举个例子

 1 public class Count{
 2     Lock lock = new Lock();
 3     public void print(){
 4         lock.lock();
 5         doAdd();
 6         lock.unlock();
 7     }
 8     public void doAdd(){
 9         lock.lock();
10         //do something
11         lock.unlock();
12     }
13 }

当调用print()方法时,得到了锁,这时就没法再调用doAdd()方法,这时必须先释放锁才能调用,因此称这种锁为不可重入锁,也叫自旋锁。

可重入锁


设计以下:

 1 public class Lock{
 2     boolean isLocked = false;
 3     Thread  lockedBy = null;
 4     int lockedCount = 0;
 5     public synchronized void lock()
 6             throws InterruptedException{
 7         Thread thread = Thread.currentThread();
 8         while(isLocked && lockedBy != thread){
 9             wait();
10         }
11         isLocked = true;
12         lockedCount++;
13         lockedBy = thread;
14     }
15     public synchronized void unlock(){
16         if(Thread.currentThread() == this.lockedBy){
17             lockedCount--;
18             if(lockedCount == 0){
19                 isLocked = false;
20                 notify();
21             }
22         }
23     }
24 }

相对来讲,可重入就意味着:线程能够进入任何一个它已经拥有的锁所同步着的代码块。

第一个线程执行print()方法,获得了锁,使lockedBy等于当前线程,也就是说,执行的这个方法的线程得到了这个锁,执行add()方法时,一样要先得到锁,因不知足while循环的条件,也就是不等待,继续进行,将此时的lockedCount变量,也就是当前得到锁的数量加一,当释放了全部的锁,才执行notify()。若是在执行这个方法时,有第二个线程想要执行这个方法,由于lockedBy不等于第二个线程,致使这个线程进入了循环,也就是等待,不断执行wait()方法。只有当第一个线程释放了全部的锁,执行了notify()方法,第二个线程才得以跳出循环,继续执行。

这就是可重入锁的特色。

java中经常使用的可重入锁

synchronized

java.util.concurrent.locks.ReentrantLock

ps:顺便记录下java中实现原子操做的类(记录至http://blog.csdn.net/huzhigenlaohu/article/details/51646455

  • AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整型数值与引用关联起来,可用于原子的更新数据和数据的版本号,能够解决使用CAS进行原子更新时可能出现的ABA问题。
  • AtomicReference :原子更新引用类型
  • AtomicReferenceFieldUpdater :原子更新引用类型里的字段
  • AtomicMarkableReference:原子更新带有标记位的引用类型。能够原子更新一个布尔类型的标记位和应用类型
  • AtomicIntegerArray :原子更新整型数组里的元素
  • AtomicLongArray :原子更新长整型数组里的元素
  • AtomicReferenceArray : 原子更新引用类型数组的元素
  • AtomicBooleanArray :原子更新布尔类型数组的元素
  • AtomicBoolean :原子更新布尔类型
  • AtomicInteger: 原子更新整型
  • AtomicLong: 原子更新长整型
相关文章
相关标签/搜索