重入锁

重入ReentrantLock

  1. 支持一个线对同一个资源进行多次加锁。
  2. 支持锁时的公平和非公平性选择

锁获取的公平性问题

对锁进取的求一定先被足,那么是公平的,反之,是不公平的。ReentrantLock提供了一个构造函数(传人一个布尔值),来控制锁是否是公平的 

1.实现

  1. 需要去识别获线程是否当前占据线程,如果是,再次成功取。 
  2. 线程重复n取了,随后在第n该锁后,其他线程才能够获取到该锁取时,数自增,锁被数自减,当数等于0表示成功放。

 

//非公平获取锁
final
boolean nonfairTryAcquire(int acquires) {   final Thread current = Thread.currentThread();   int c = getState();   if (c == 0) {     if (compareAndSetState(0, acquires)) {       setExclusiveOwnerThread(current);       return true;     }   } else if (current == getExclusiveOwnerThread()) {     int nextc = c + acquires;//成功获取锁的线程再次获取锁,只是增加了同步状态值     if (nextc < 0)
       throw new Error("Maximum lock count exceeded");
    setState(nextc);
    return true;
  }   
return false; }

 

//释放锁
protected
final boolean tryRelease(int releases) {   int c = getState() - releases;//在释放同步状态时减少同步状态值   if (Thread.currentThread() != getExclusiveOwnerThread())     throw new IllegalMonitorStateException();   boolean free = false;   if (c == 0) {     free = true;     setExclusiveOwnerThread(null);   }   setState(c);   return free; }

 

2.公平与非公平

  公平与非公平锁的别 :序是否符合FIFO 

//公平获取锁
protected final boolean tryAcquire(int acquires) {
  final Thread current = Thread.currentThread();
  int c = getState();
  if (c == 0) {
    if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
      setExclusiveOwnerThread(current);
      
return true;     }   } else if (current == getExclusiveOwnerThread()) {     int nextc = c + acquires;     if (nextc < 0)       throw new Error("Maximum lock count exceeded");     setState(nextc);     return true;   }
  return
false; }

方法与nonfairTryAcquire(int acquires),唯一不同的位置判断条件多了hasQueuedPredecessors()方法,即加入了同步列中当前点是否有前驱节点的判断,如果该方法返回true表示有线程比当前线程更早地,因此需要等待前驱线取并释放之后才能继续获锁 

测试公平和非公平锁时的区

public class FairAndUnfairTest {
  private static Lock fairLock = new ReentrantLock2(true);
  private static Lock unfairLock = new ReentrantLock2(false);
  @Test
  public void fair() {
    testLock(fairLock);
  } 
  @Test   
public void unfair() {     testLock(unfairLock);   }
  private
void testLock(Lock lock) {     // 启动5个Job(略)   }
  private
static class Job extends Thread {     private Lock lock;     public Job(Lock lock) {       this.lock = lock;     }
    public
void run() {// 连续2次打印当前的Thread和等待队列中的Thread(略)     }   }
  private
static class ReentrantLock2 extends ReentrantLock {     public ReentrantLock2(boolean fair) {       super(fair);     }
    public Collection
<Thread> getQueuedThreads() {       List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());       Collections.reverse(arrayList);       return arrayList;     }   } }

 

 

 

 察表5-6所示的果(其中每个数字代表一个线程),公平性每次都是从同步列中的第一个取到,而非公平性了一个线连续获的情况。 由于刚释线程再次获取同步状的几率会非常大 ,这样就减少了因锁切换而导致的线程上下文切换的开销



 

posted on 2017-02-18 10:29  近博  阅读(1007)  评论(0编辑  收藏  举报

导航