Java并发之(3):锁

    锁是并发编程中的重要概念,用来控制多个线程对同一资源的并发访问,在支持并发的编程语言中都有体现,好比c++ python等。本文主要讲解Java中的锁,或者说是重入锁。之因此这么说是由于在Java中,锁主要就是指重入锁。 java中的锁分为两大类:一种是synchronized内置锁,另外一种是显式的Lock锁。在Java中,Lock接口的主要实现是重入锁ReentrantLock,而内置锁也是可重入锁。html

    这两种锁的简单比较以下:java

    synchronized内置锁和ReentrantLock都是可重入锁。 synchronized就不是可中断锁,而Lock是可中断锁。  synchronized 和Lock都是不公平锁。 Lock能够设置为公平锁。    node

    在nts 生产代码中,并无使用显式Lock,而是大量地使用了synchronized关键字。本文主要包括这两种锁的实现、主要的方法和使用。其中在讲解使用时,会结合在jdk中的使用以及在nts中的使用等方式来说解。python

outline:
1 java 的内置锁(synchronized关键字的使用
2 ReentrantLock的实现、主要方法和使用c++

3 Condition的实现、主要方法和使用编程

4 ReentrantReadWriteLock的实现、主要方法和使用并发



1 java 的内置锁(synchronized关键字)的使用

    synchronized 关键字有两种用法:synchronized 方法和 synchronized 块。其中synchronized方法又分为静态方法和实例方法两种。synchronized块又能够分为普通对象块,this对象块和class对象块。因为能够针对任意代码块,且可任意指定上锁的对象,故synchronized块的灵活性较高。app

    当一个线程获取了对应的内置锁,并执行该代码块时,其余线程便只能一直等待获取锁的线程释放锁,而获取锁的线程只会在两种状况下释放锁:

  1)获取锁的线程执行完了该代码块,而后释放对锁的占有;

  2)线程执行发生异常,此时JVM会让线程自动释放锁。

1.1 synchronized 方法:框架

 1 // in push.Latch      
 2 public synchronized void enter(final long timeout) throws InterruptedException //经过在方法声明中加入 synchronized关键字来声明 synchronized 方法  3       {
 4          num++;
 5          if (num < total)
 6          {
 7             if (0L < timeout)
 8             {
 9                wait(timeout); // here InterruptedException may be thrown 10             }
11          }
12          else
13          {
14             notifyAll(); // must in a synchronized method 15          }
16       }

 

1.2 static synchronized 方法less

static synchronized方法是对class的类对象加锁,synchronized方法是对class的当前object加锁。

 1 // in dca.access.IconStore   
 2 public static synchronized IconStore getInstance()  // 性能较差的singleton模式  3    {
 4       try
 5       {
 6          if (null == instance)
 7          {
 8             instance = new IconStore();
 9          }
10       }
11       catch (final NotesException e)
12       {
13          XLog.error("Could not create icon store object", e);
14       }
15 
16       return instance;
17    }

 

1.3 普通对象上的synchronized 块

 1 //nts.util.Events    
private static final Map<String, SignalValues> events = new HashMap<String, SignalValues>()
...
2 public Object clone() 3 { 4 Events s = null; 5 6 try 7 { 8 synchronized (events) // on plain object 9 { 10 s = (Events) super.clone(); 11 } 12 } 13 catch (final CloneNotSupportedException e) 14 { 15 XLog.error(e); 16 } 17 return s; 18 }

 
1.4 类对象上的synchronized 块

 1   private static TravelerSocketFactory getInstance() // in util.TravelerSocketFactory  2    {
 3       if (instance == null) 
 4       {
 5          synchronized (TravelerSocketFactory.class) // double-checking lock  6          {
 7             if (instance == null)
 8             {
 9                instance = new TravelerSocketFactory();
10             }
11          }
12       }
13       return instance;
14    }

 

1.5  this 对象上synchronized 块

 1 // in push.Latch   
 2 public boolean start(final Object obj)
 3    {
 4       final long timeStart = System.currentTimeMillis();
 5       boolean rv = false;
 6       Barrier b = null;
 7       synchronized (this) // 当前对象  8       {
 9          if (!latched.containsKey(obj))
10          {
11             b = new Barrier("Latch:" + name + "_Obj:" + obj, 1);
12             latched.put(obj, b);
13             rv = true;
14          }
15       }
16       XLog.exiting("name=" + name, "obj=" + obj, "barrier=" + b, "rv=" + rv, ("Elapsed time="
17             + (System.currentTimeMillis() - timeStart) + "ms"));
18       return rv;
19    }

 

1.6 Java内置锁的可重入性

下面这段code能够证实对象关联monitor上的锁是重入锁。若是锁具有可重入性,则称做为可重入锁。一个线程不能获取其余线程所拥有的锁,可是它能够获取它已经拥有的锁。 容许一个线程屡次获取同一个锁,使得重入同步成为可能。考虑如下场景:同步代码(位于同步块或者同步方法中的代码)直接或者间接地调用某个方法,而该方法 一样包含同步代码(上述两组代码使用一样的锁)。若是没有重入同步,同步代码将不得不使用额外的预警机制来避免一个线程由于本身阻塞本身而死锁。可重入性 在我看来实际上代表了锁的分配机制:基于线程的分配,而不是基于方法调用的分配。

 1 class Test {
 2   public static void main(String[] args) {
 3     Test t = new Test();
 4     synchronized(t) {
 5       synchronized(t) {
 6         System.out.println("made it!");
 7       }
 8     }
 9   }
10 }

程序的输出结果为:

1 made it!
View Code

 在JICP中举了一个例子,是两个synchronized方法。其中一个调用了另一个。若是不是可重入锁,则会死锁。


2 jdk中的显式Lock

 

java.util.concurrent包是java5的一个重大改进,java.util.concurrent包提供了多种线程间同步和通讯的机制,好比Executors, Queues, Timing, Synchronizers和Concurrent Collections等。其中Synchronizers包含了五种:Semaphore信号量,CounDownLatch倒计时锁存器,CyclicBarrier循环栅栏,Phaser和Exchanger。 另外java.util.concurrent包还包含了两个子包:java.util.concurrent.Atomics和java.util.concurrent.Locks。


2.1 Lock接口的方法及使用
Lock接口一共定义了如下6个不一样的方法:其中lock()、lockInterruptibly(), TryLock()、和tryLock(long time, TimeUnit unit))是用来获取锁的。unLock()方法是用来释放锁的。newCondition() 用来生成新的Condition对象。(跟Lock用来替代Synchronized相似,Condition用来替代object monitor上的wait()/notify()方法。) 下面分别来介绍这些方法的使用:
 
2.1.1  void lock()

Lock接口获取锁的方式有4中,首先lock()方法是日常使用得最多的一个方法,就是用来获取锁。若是锁已被其余线程获取,则进行等待。(跟synchronized同样,可使用synchronized代替lock。)

 1 // java.util.concurrent.CyclicBarrier    
 2 public boolean isBroken() {
 3         final ReentrantLock lock = this.lock; // this.lock is a feild in CyclicBarrier, this is a optimize method which is heavily used by doug lea 
 4         lock.lock();
 5         try {
 6             return generation.broken;
 7         } finally {
 8             lock.unlock();
 9         }
10     }

 

lock()的不正确使用方法示例:

 1 public class Test {
 2     private ArrayList<Integer> arrayList = new ArrayList<Integer>();
 3     public static void main(String[] args)  {
 4         final Test test = new Test();
 5          
 6         new Thread(){
 7             public void run() {
 8                 test.insert(Thread.currentThread());
 9             };
10         }.start();
11          
12         new Thread(){
13             public void run() {
14                 test.insert(Thread.currentThread());
15             };
16         }.start();
17     }  
18      
19     public void insert(Thread thread) {
20         Lock lock = new ReentrantLock();    //注意这个地方
21         lock.lock();
22         try {
23             System.out.println(thread.getName()+"获得了锁");
24             for(int i=0;i<5;i++) {
25                 arrayList.add(i);
26             }
27         } catch (Exception e) {
28             // TODO: handle exception
29         }finally {
30             System.out.println(thread.getName()+"释放了锁");
31             lock.unlock();
32         }
33     }
34 }

 

2.1.2  boolean tryLock()方法

在当前时间(被调用时)查询锁是否可用。若是不可用则当即返回。

 1 // java.util.concurrent.ForkJoinTask  
 2 static final void helpExpungeStaleExceptions() {
 3         final ReentrantLock lock = exceptionTableLock;
 4         if (lock.tryLock()) {
 5             try {
 6                 expungeStaleExceptions();
 7             } finally {
 8                 lock.unlock();
 9             }
10         }
11     }

 

2.1.3 void lockInterruptibly() throws InterruptedException;

这个方法涉及到一个概念,可中断锁。顾名思义,就是能够响应中断的锁。若是某一线程A正在执行锁中的代码,另外一线程B正在等待获取该锁,可能因为等待时间过长,线程B不想等待了,想先处理其余事情,咱们可让它中断本身或者在别的线程中中断它,这种就是可中断锁。单独调用interrupt()方法不能中断正在运行过程当中的线程,只能中断阻塞过程当中的线程。用synchronized修饰的话,当一个线程处于等待 某个锁的状态,是没法被中断的,只有一直等待下去。Lock可让等待锁的线程响应中断,而synchronized却不行,使用 synchronized时,等待的线程会一直等待下去,不可以响应中断(在threadA中调用threadB.interrupt();)。

// java.util.concurrent.ArrayBlockingQueue    
public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly(); // can be interrupted here try {
            while (count == items.length)
                notFull.await(); // notFull is a Condition of lock.
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

 
2.1.4 boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
在jdk和nts生产代码中没有该方法的使用。

2.1.5 Condition newCondition();

用来返回一个Condition接口的对象,Condition对象的使用见下一节。

2.1.6 void unlock();

采用synchronized不须要用户去手动释放 锁,当synchronized方法或者 synchronized代码块执行完以后,系统会自动让线程释放对锁的占用;而Lock则必需要用户去手动释放锁,若是没有主动释放锁,就有可能致使出 现死锁现象。 synchronized在发生异常时,会自动释放线程占有的锁,所以不会致使死锁现象发生;而Lock在发生异常时,若是没有主动经过unLock() 去释放锁,则极可能形成死锁现象,所以使用Lock时须要在finally块中释放锁。

 1  public boolean addAll(Collection<? extends E> c) { // java.util.concurrent.CopyOnWriteArrayList  2 Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?  3 ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();  4 if (cs.length == 0)  5 return false;  6 final ReentrantLock lock = this.lock;  7  lock.lock();  8 try {  9 Object[] elements = getArray(); 10 int len = elements.length; 11 if (len == 0 && cs.getClass() == Object[].class) 12  setArray(cs); 13 else { 14 Object[] newElements = Arrays.copyOf(elements, len + cs.length); 15 System.arraycopy(cs, 0, newElements, len, cs.length); 16  setArray(newElements); 17  } 18 return true; 19 } finally { 20  lock.unlock(); 21  } 22 }

 

2.2 ReentrantLock的实现

ReentrantLock内部有一个Sync内部类,它是抽象类AQS(abstractQueuedSychronizer)的子类,它又有两个子类NonFairSync和FairSync。 ReentrantLock的上述方法都是经过Sync内部类来实现的。

newCondition():可见ReentrantLock的实现基本彻底基于AQS,ReentrantLock返回的Condition对象,是它的AQS内部类的内部类ConditionObject的实例(在下一节会详述):

1     public Condition newCondition() { 2 return sync.newCondition(); 3 }

lock(): 包裹了sync内部类的lock方法。

1    public void lock() { 2  sync.lock(); 3 }

 tryLock():

1     public boolean tryLock(long timeout, TimeUnit unit) 2 throws InterruptedException { 3 return sync.tryAcquireNanos(1, unit.toNanos(timeout)); 4 }

 lockInterruptibly():

1     public void lockInterruptibly() throws InterruptedException { 2 sync.acquireInterruptibly(1); 3 }

 unLock():

1   public void unlock() { 2 sync.release(1); 3 }

 

下面再来看一下ReentrantLock如何实现公平锁和非公平锁(公平锁:当持有该锁的线程释放掉公平锁的时候,等待该锁的其余线程得到该锁的机会均等,不存在某个线程屡次得到该锁,而其余某个线程一直处在饥饿状态的状况。)

FairSync:

 1         protected final boolean tryAcquire(int acquires) {  2 final Thread current = Thread.currentThread();  3 int c = getState();  4 if (c == 0) {  5 if (!hasQueuedPredecessors() && // 若是处于等待队列的最前面  6 compareAndSetState(0, acquires)) {  7  setExclusiveOwnerThread(current);  8 return true;  9  } 10  } 11 else if (current == getExclusiveOwnerThread()) { 12 int nextc = c + acquires; 13 if (nextc < 0) 14 throw new Error("Maximum lock count exceeded"); 15  setState(nextc); 16 return true; 17  } 18 return false; 19  } 20 }

 

 NonFairSync():

 1         final boolean nonfairTryAcquire(int acquires) {  2 final Thread current = Thread.currentThread();  3 int c = getState();  4 if (c == 0) {  5 if (compareAndSetState(0, acquires)) { // 直接开抢,谁抢着谁执行  6  setExclusiveOwnerThread(current);  7 return true;  8  }  9  } 10 else if (current == getExclusiveOwnerThread()) { 11 int nextc = c + acquires; 12 if (nextc < 0) // overflow 13 throw new Error("Maximum lock count exceeded"); 14  setState(nextc); 15 return true; 16  } 17 return false; 18 }

 

公平锁和非公平锁能够经过ReentrantLock的构造函数来实现,默认构造函数用来构造NonFairLock, 而带参数的public ReentrantLock(boolean fair) 方法能够选择构造NonFairLock仍是FairLock。

1  public ReentrantLock() { 2 sync = new NonfairSync(); 3 }

带参数构造函数:

1  public ReentrantLock(boolean fair) { 2 sync = fair ? new FairSync() : new NonfairSync(); 3 }

 

 ReentrantLock 还提供了几个查询方法:getHoldCount,isHoldByCurrentThread,isLocked, isFair, getOwner, hasQueuedThreads, getQueueLength, 等等,再也不赘述。

 

3 Condition的实现、主要方法和使用

Lock与Condition的组合,能够用来替代Synchronized&wait/notify的组合。

3.1 实现

如前所述,Condition的实现也离不开AQS。

返回函数:

1   public Condition newCondition() { // in java.util.concurrent.ReentrantLock 2 return sync.newCondition(); 3 }

sync是什么呢? 在 ReentrantLock类中定义了一个抽象class Sync(抽象类AQS的子类),它又有两个子类FairSync和NonFairSync。上面代码中的sync就是NonFairSync的对象。

1 abstract static class Sync extends AbstractQueuedSynchronizer { 2  ... 3 final ConditionObject newCondition() { 4 return new ConditionObject(); 5  } 6  ... 7 }

在java中实现了 Conditon接口的类只有两 个:AbstractQueuedSynchronizer.ConditionObject和 AbstractLongQueuedSynchronized.ConditionObject。

3.2 方法

Condition接口经过提供下列方法,提供了与Object.notify()/Object.notifyAll()相似的功能:

 1 //能够被中断,无期限等待。
 2 void await() throws InterruptedException;
 3 //无期限等待,不可中断。
 4 void awaitUninterruptibly();
 5 //等待特定时间,超时则返回;可中断。返回值是返回时距离超时所剩时间。
 6 long awaitNanos(long nanosTimeout) throws InterruptedException;
 7 //等待特定时间,超时则返回;可中断。超时返回,返回值为false。
 8 boolean await(long time, TimeUnit unit) throws InterruptedException;
 9 //等待到特定时间点,超时则返回;可中断。超时返回,返回值为false。
10 boolean awaitUntil(Date deadline) throws InterruptedException;
11 void signal();
12 void signalAll();

 

 

3.3 CyclicBarrier中的使用

下面以java.util.concurrent包下的CyclicBarrier和BlockingQueue(接口)为例,来看一下这些方法的使用,首先看一下CyclicBarrier中的:

NewCondition():

1 // in CyclicBarrier 2 /** The lock for guarding barrier entry */ 3 private final ReentrantLock lock = new ReentrantLock(); 4 /** Condition to wait on until tripped */ 5 private final Condition trip = lock.newCondition();

  

signalAll():

1     private void nextGeneration() {
3         // signal completion of last generation
4  trip.signalAll(); 5         // set up next generation
6         count = parties;
7         generation = new Generation();
8     }

 

 await()&awaitNanos(long):

 1  private int dowait(boolean timed, long nanos) // CyclicBarrier  2         throws InterruptedException, BrokenBarrierException,
 3                TimeoutException {
 4         final ReentrantLock lock = this.lock;  5         lock.lock();
 6         try {
 7             final Generation g = generation;
 8 
 9             if (g.broken)
10                 throw new BrokenBarrierException();
11 
12             if (Thread.interrupted()) {
13                 breakBarrier();
14                 throw new InterruptedException();
15             }
16 
17             int index = --count; // count is how many thread will be barriered 18             if (index == 0) {  // tripped
19                 boolean ranAction = false;
20                 try {
21                     final Runnable command = barrierCommand;
22                     if (command != null)
23  command.run(); 24                     ranAction = true;
25                     nextGeneration();
26                     return 0;
27                 } finally {
28                     if (!ranAction)
29                         breakBarrier();
30                 }
31             }
32 
33             // loop until tripped, broken, interrupted, or timed out
34             for (;;) { 35                 try {
36                     if (!timed)
37  trip.await(); 38                     else if (nanos > 0L)
39                         nanos = trip.awaitNanos(nanos); 40                 } catch (InterruptedException ie) {
41                     if (g == generation && ! g.broken) {
42                         breakBarrier();
43                         throw ie;
44                     } else {
45                         // We're about to finish waiting even if we had not
46                         // been interrupted, so this interrupt is deemed to
47                         // "belong" to subsequent execution.
48                         Thread.currentThread().interrupt();
49                     }
50                 }
51 
52                 if (g.broken)
53                     throw new BrokenBarrierException();
54 
55                 if (g != generation)
56                     return index;
57 
58                 if (timed && nanos <= 0L) {
59                     breakBarrier();
60                     throw new TimeoutException();
61                 }
62             }
63         } finally { 64  lock.unlock(); 65  } 66     }

 

3.4 ArrayBlockingQueue中的使用:

newCondition():

能够为一个重入锁设置多个Condition对象

1     public ArrayBlockingQueue(int capacity, boolean fair) {
2         if (capacity <= 0)
3             throw new IllegalArgumentException();
4         this.items = new Object[capacity];
5         lock = new ReentrantLock(fair); 6         notEmpty = lock.newCondition(); 7         notFull = lock.newCondition(); 8     }

 signal():

 1     public void put(E e) throws InterruptedException {
 2         checkNotNull(e);
 3         final ReentrantLock lock = this.lock;
 4         lock.lockInterruptibly();
 5         try {
 6             while (count == items.length)  7  notFull.await();  8  enqueue(e);  9         } finally {
10             lock.unlock();
11         }
12     }

 

3.5 LinkedBlockingQueue中的使用

new:

1     /** Lock held by put, offer, etc */
2     private final ReentrantLock putLock = new ReentrantLock();
3 
4     /** Wait queue for waiting puts */
5     private final Condition notFull = putLock.newCondition();

 

 signal():

 1 public void put(E e) throws InterruptedException {
 2         if (e == null) throw new NullPointerException();
 3         // Note: convention in all put/take/etc is to preset local var
 4         // holding count negative to indicate failure unless set.
 5         int c = -1;
 6         Node<E> node = new Node<E>(e);
 7         final ReentrantLock putLock = this.putLock;
 8         final AtomicInteger count = this.count;
 9  putLock.lockInterruptibly(); 10         try {
11             while (count.get() == capacity) {
12  notFull.await(); 13             }
14             enqueue(node);
15             c = count.getAndIncrement();
16             if (c + 1 < capacity)
17  notFull.signal(); 18         } finally { 19  putLock.unlock(); 20  } 21         if (c == 0)
22             signalNotEmpty();
23     }

 

4 读写锁 ReadWriteLock 接口
 
ReadWriteLock接口只提供两个方法定义,其中readLock()方法返回一个ReentrantLock.ReadLock类的对象做为 readLock,另外一个writeLock()方法返回一个ReentrantLock.WriteLock类的对象做为writeLock。

当没有写线程时,readLock能够被多个读线程同时持有(互斥锁:在任一时刻只容许一个线程持有,其余线程将被阻塞。 与之对应的是共享锁(S锁,share)又称读锁。)。而写锁则是互斥的: 一些锁容许对共享资源的并发访问,好比一个readWriteLock中的读锁。


若是有一个线程已经占用了读锁,则此时其余线程若是要申请写锁,则申请写锁的线程会一直等待释放读锁。
若是有一个线程已经占用了写锁,则此时其余线程若是申请写锁或者读锁,则申请的线程会一直等待释放写锁。

4.1 示例:

 1 import java.util.concurrent.*;
 2 import java.util.Date;
 3 import java.util.concurrent.locks.*;
 4 import java.text.*;
 5 
 6 public class ReentrantReadWriteLockTest {
 7   private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 8   private SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
 9   private Lock readLock = readWriteLock.readLock();
10   private Lock writeLock = readWriteLock.writeLock();
11 
12   public void read() {
13     readLock.lock();
14     try {
15       System.out.println(format.format(new Date()) + "---read---");
16       TimeUnit.SECONDS.sleep(3);
17     } catch (InterruptedException e) {
18       e.printStackTrace();
19     } finally {
20       readLock.unlock();
21     }
22   }
23 
24   public void write() {
25     writeLock.lock();
26     try {
27       System.out.println(format.format(new Date()) + "---write---");
28       TimeUnit.SECONDS.sleep(3);
29     } catch (InterruptedException e) {
30       e.printStackTrace();
31     } finally {
32       writeLock.unlock();
33     }
34   }
35 
36   public static class MyThread extends Thread {
37     private ReentrantReadWriteLockTest reentrantReadWriteLockTest;
38     private String methodName;
39 
40     public MyThread(ReentrantReadWriteLockTest reentrantReadWriteLockTest, String methodName) {
41       super();
42       this.reentrantReadWriteLockTest = reentrantReadWriteLockTest;
43       this.methodName = methodName;
44     }
45 
46     @Override
47     public void run() {
48       if ("read".equalsIgnoreCase(methodName))
49         reentrantReadWriteLockTest.read();
50       else
51         reentrantReadWriteLockTest.write();
52     }
53   }
54 
55   public static void main(String[] args) {
56     ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest();
57     Thread t1 = new MyThread(test, "write"); // replace write with read and check what will happen? 58     Thread t2 = new MyThread(test, "read");
59     t1.start();
60     t2.start();
61   }
62 }

 


4.2 使用

读写锁的典型应用场景为对容器的读写。可是,java的容器框架提供了各类各样的免锁或并发容器,好比最简单的并发容器Collections.synchronizedMap()等等。

在免锁容器中,CopyOnWriteArrayList对读操做不会block,对写操做会block;ConcurrentHashMap 类将 Map 的存储空间分为若干块,每块拥有本身的锁,大大减小了多个线程争夺同一个锁的状况: 对读操做不会block 即便是对写操做,咱们也不须要对整个Map对象加锁,从而避免在整个对象上block。所以读写锁的应用并非特别普遍。

下面来看一下jdk中使用ReentantreadWriteLock的例子javax.swing.plaf.nimbus.ImageCache :

1     // Lock for concurrent access to map
2     private ReadWriteLock lock = new ReentrantReadWriteLock();

 flush:

为何flush方法加读锁?

1     public void flush() {
2  lock.readLock().lock(); 3         try {
4             map.clear();
5         } finally {
6             lock.readLock().unlock();
7         }
8     }

 getImage:

 1     public Image getImage(GraphicsConfiguration config, int w, int h, Object... args) {
 2  lock.readLock().lock();  3         try {
 4             PixelCountSoftReference ref = map.get(hash(config, w, h, args));
 5             // check reference has not been lost and the key truly matches, in case of false positive hash match
 6             if (ref != null && ref.equals(config,w, h, args)) {
 7                 return ref.get();
 8             } else {
 9                 return null;
10             }
11         } finally {
12             lock.readLock().unlock();
13         }
14     }

setImage:

 1     public boolean setImage(Image image, GraphicsConfiguration config, int w, int h, Object... args) {
 2         if (!isImageCachable(w, h)) return false;
 3         int hash = hash(config, w, h, args);
 4  lock.writeLock().lock();  5         try {
 6            //...
 7         } finally {
 8             lock.writeLock().unlock();
 9         }
10     }

 

问题: 与ConcurrentHashMap相比,读写锁的优点在哪里?


4.3 ReentrantReadWireteLock的实现:
内部一样是定义了NonFair和Fair的synchronizer,一样是继承自AQS。


5 进一步问题:



自旋锁:
基于他这种原理,等待的时候,并不释放cpu时间片,相比synchronized  wait()操做,减少了释放,从新获取的消耗。 该自旋锁适用于,当前线程竞争不强烈的时候使用。

 进一步解释synchronized和显式Lock的区别
 
在性能上来讲,若是竞争资源不激烈,二者的性能是差很少的,而当竞争资源很是激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。 ??


6 参考文献:
http://www.cnblogs.com/dolphin0520/p/3923167.html

http://blog.csdn.net/HEYUTAO007/article/details/6422412

相关文章
相关标签/搜索