`
jimichan
  • 浏览: 277937 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Concurrent In Java 6 分享,第三部分 锁

    博客分类:
  • java
阅读更多

第一部分 集合 http://jimichan.iteye.com/blog/951948

 

第二部分 线程池 http://jimichan.iteye.com/blog/951950

 

第三部分 锁 http://jimichan.iteye.com/blog/951954

 

第四部分 同步辅助类 http://jimichan.iteye.com/blog/951955

Concurrent In Java,第三部分 锁

 

2011-3-9  延昭 & 陈汝烨 版权所有,特别禁止发布到百度文库

这篇是来自公司内部分享会议是写的总结,有些内容没有表达出来,大家可以来踩,但是需留下原因,以便后续补充。

3. java.util.concurrent.locks

 

java 早期内置synchronized关键字解决多线程对共享资源访问的一些问题,和其还配套了Object的notify 和 wait方法,用来控制线程之间的同步。

 

concurrent软件包提供了更为高级和抽象的Lock工具,能解决更多的问题。

 

Lock是控制多个线程对共享资源进行访问的工具。通常Lock限定多线程对同一个共享资源访问的限制,一次只允许一个线程获得Lock,即获得对共享资源的访问权限,线程间是互斥的。但是也有一些锁如果ReadWriteLock是允许部分线程同时访问共享资源的。

 

 

几个术语:

 

争用:当多个Thread在同一时间内(相对概念)想要占有同一个Lock对象。那么JVM会调度解决争用。

 

获取顺序:当多个线程争用同一个Lock对象,那么JVM就要决定哪个线程将会获得锁权限。存在两种模式:公平不公平。 默认都是不公平模式,包括synchronized关键字,jvm决定顺序的时候也是采用不公平策略。因为公平策略需要系统记录大量辅助信息来判断分配顺序,而不公平策略由JVM决定一直快速高效的算法来分配Lock。所以不公平策略的系统吞吐量会比较高(花费更少的空间和计算在分配上),如果没有特殊需要则默认采用不公平策略。

 

重入:当前线程获取指定的锁对象权限后,还可以再次获取该锁。Lock内部会有一个计数器来表明当前线程获取了该锁的数量。如果一个线程获取了一个锁两次,那么线程必须释放锁两次,才能被看作完全释放了该锁,所以编程的时候一定要注意使用重入。synchronized关键字也是支持重入语义的。

3.1 Lock & ReentrantLock

ReentrantLock实现了Lock接口,一个可重入(reentrant)的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

 

摘自JavaDoc的一段获取规则 “当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。”

 

经典使用方法。

public void m() { 
    lock.lock();  // block until condition holds
    try {
      // ... method body
    } finally {
      lock.unlock()
    }
  }

 

 

ReentrantLock除了实现了Lock规定的方法外,还实现了tryLock、isLocked 等方法,帮助你实现更多的场景。

 

Condition

和Object的wait和notify方法类似。ReentrantLock对象附加了Conditon对象,用来完成挂起和唤醒操作,使用lock.newCondition() 方法生成。

一个来自JKD的例子:

class BoundedBuffer {
  
final Lock lock = new ReentrantLock();
  final Condition notFull  = 
lock.newCondition(); 
  final Condition notEmpty = 
lock.newCondition(); 

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(Object x) throws InterruptedException {
    
lock.lock();
    try {

      while (count == items.length) 
        
notFull.await();
      items[putptr] = x; 
      if (++putptr == items.length) putptr = 0;
      ++count;
      
notEmpty.signal();
    
} finally {
      lock.unlock();
    }

  }

  public Object take() throws InterruptedException {
    
lock.lock();
    try {

      while (count == 0) 
        
notEmpty.await();
      Object x = items[takeptr]; 
      if (++takeptr == items.length) takeptr = 0;
      --count;
      
notFull.signal();
      return x;
    
} finally {
      lock.unlock();
    }

  } 
}

 

利用Conditon对象可以让所有对同一个锁对象进行争用的Thread之间进行同步。

 

 

Lock VS synchronized

除非你有明确的需求或者并发遇到瓶颈的时候再决定使用ReentrantLock。synchronized在大部分时候还是可以工作的很好,jvm会自动处理和回收锁。

 

ReentrantLock提供了更多的选择和状态信息。和

 

 

3.2 ReadWriteLock & ReentrantReadWriteLock

列举一个场景对象X,拥有方法a、b、c。a和b方法不改表X的内部状态,c改变内部状态。在多线程环境下,我们要求只读和写(变更状态)是不能同时进行的,而只读操作是可以同时并发的,且实际运行过程中读操作数量远远大于写操作的数量。

 

如果用synchronized关键字的话,两个只读方法a、b也会互斥,并发性能收到限制。

 

那么这个情况下ReadWriteLock就非常有用,使用也非常简单。

 

class RWDictionary {
   private final Map<String, Data> m = new TreeMap<String, Data>();
   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
   private final Lock r = rwl.readLock();
   private final Lock w = rwl.writeLock();

   public Data get(String key) {
       r.lock();
       try { return m.get(key); }
       finally { r.unlock(); }
   }
   public String[] allKeys() {
       r.lock();
       try { return m.keySet().toArray(); }
       finally { r.unlock(); }
   }
   public Data put(String key, Data value) {
       w.lock();
       try { return m.put(key, value); }
       finally { w.unlock(); }
   }
   public void clear() {
       w.lock();
       try { m.clear(); }
       finally { w.unlock(); }
   }
}

 

 

要记得write锁是独占的,它一样可以使用ReentrantLock的Condition功能。

 

使用任何的锁都要通过try catch 或者 finally 来处理异常,避免忘记unlock。

 

 

第四部分 同步辅助类

http://jimichan.iteye.com/blog/951955

 

 

2
6
分享到:
评论

相关推荐

    JAVA_API1.6文档(中文)

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing....

    Java 1.6 API 中文 New

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing.border ...

    JavaAPI1.6中文chm文档 part1

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing....

    java api最新7.0

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing.border ...

    java高级特性整理资料(反射+并发+jvm)

    包含java三大高级特性的文档,《Java Reflection in Action》、《JAVA并发编程实战》、《JVM调优总结》、《深入理解Java虚拟机JVM高级特性与最佳实践》、《concurrent programming in java》,适合想深入java技术的...

    JavaAPI中文chm文档 part2

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing....

    [Java参考文档]

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing....

    [Java参考文档].JDK_API 1.6

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing.border ...

    java 面试题 总结

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    JDK_1_6 API

    javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些组件在所有平台上的工作方式都相同。 javax.swing.border...

    超级有影响力霸气的Java面试题大全文档

    超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    sesvc.exe 阿萨德

    CSS3 Linux C++ Python C# Node.Js 一文让你彻底理解 Java HashMap 和 ConcurrentHashMap 2018-07-25 分类:JAVA开发、编程开发、首页精华0人评论 来源:crossoverjie.top 分享到:更多0 前言 Map 这样的...

Global site tag (gtag.js) - Google Analytics