`

实战Concurrent(2)

阅读更多

来自http://www.iteye.com/topic/363625

 

2、Lock

多线程编程中常常要锁定某个对象,之前会用synchronized来实现,现在又多了另一种选择,那就是java.util.concurrent.locks。通过Lock能够实现更灵活的锁定机制,它还提供了很多synchronized所没有的功能,例如尝试获得锁(tryLock())。

 

使用Lock时需要自己获得锁并在使用后手动释放,这一点与synchronized有所不同,所以通常Lock的使用方式是这样的:

Java代码 
  1. Lock l = ...;   
  2. l.lock();  
  3. try  {  
  4.     // 执行操作   
  5. finally  {  
  6.     l.unlock();  
  7. }  

 

java.util.concurrent.locks中提供了几个Lock接口的实现类,比较常用的应该是ReentrantLock。以下范例中使用了ReentrantLock进行节点锁定:

Java代码 
  1. package  service;  
  2.   
  3. import  java.util.concurrent.locks.Lock;  
  4. import  java.util.concurrent.locks.ReentrantLock;  
  5.   
  6. /**  
  7.  * 节点类  
  8.  *   
  9.  * @author DigitalSonic  
  10.  */   
  11. public   class  Node {  
  12.     private  String name;  
  13.     private  String wsdl;  
  14.     private  String result =  "PASS" ;  
  15.     private  String[] dependencies =  new  String[] {};  
  16.     private  Lock lock =  new  ReentrantLock();  
  17.     /**  
  18.      * 默认构造方法  
  19.      */   
  20.     public  Node() {  
  21.     }  
  22.       
  23.     /**  
  24.      * 构造节点对象,设置名称及WSDL  
  25.      */   
  26.     public  Node(String name, String wsdl) {  
  27.         this .name = name;  
  28.         this .wsdl = wsdl;  
  29.     }  
  30.   
  31.     /**  
  32.      * 返回包含节点名称、WSDL以及验证结果的字符串  
  33.      */   
  34.     @Override   
  35.     public  String toString() {  
  36.         String toString = "Node: "  + name +  " WSDL: "  + wsdl +  " Result: "  + result;  
  37.         return  toString;  
  38.     }  
  39.       
  40.     // Getter & Setter   
  41.     ...
  42.   
  43. }  
Java代码 
  1. package  service;  
  2.   
  3. import  java.util.concurrent.Callable;  
  4. import  java.util.concurrent.locks.Lock;  
  5. import  java.util.logging.Logger;  
  6.   
  7. import  service.mock.MockNodeValidator;  
  8.   
  9. /**  
  10.  * 执行验证的任务类  
  11.  *   
  12.  * @author DigitalSonic  
  13.  */   
  14. public   class  ValidationTask  implements  Callable<Node> {  
  15.     private   static  Logger logger = Logger.getLogger( "ValidationTask" );  
  16.   
  17.     private  String        wsdl;  
  18.   
  19.     /**  
  20.      * 构造方法,传入节点的WSDL  
  21.      */   
  22.     public  ValidationTask(String wsdl) {  
  23.         this .wsdl = wsdl;  
  24.     }  
  25.   
  26.     /**  
  27.      * 执行针对某个节点的验证<br/>  
  28.      * 如果正有别的线程在执行同一节点的验证则等待其结果,不重复执行验证  
  29.      */   
  30.     @Override   
  31.     public  Node call()  throws  Exception {  
  32.         Node node = ValidationService.NODE_MAP.get(wsdl);  
  33.         Lock lock = null ;  
  34.         logger.info("开始验证节点:"  + wsdl);  
  35.         if  (node !=  null ) {  
  36.             lock = node.getLock();  
  37.             if  (lock.tryLock()) {  
  38.                 // 当前没有其他线程验证该节点   
  39.                 logger.info("当前没有其他线程验证节点"  + node.getName() +  "["  + wsdl +  "]" );  
  40.                 try  {  
  41.                     Node result = MockNodeValidator.validateNode(wsdl);  
  42.                     mergeNode(result, node);  
  43.                 } finally  {  
  44.                     lock.unlock();  
  45.                 }  
  46.             } else  {  
  47.                 // 当前有别的线程正在验证该节点,等待结果   
  48.                 logger.info("当前有别的线程正在验证节点"  + node.getName() +  "["  + wsdl +  "],等待结果" );  
  49.                 lock.lock();  
  50.                 lock.unlock();  
  51.             }  
  52.         } else  {  
  53.             // 从未进行过验证,这种情况应该只出现在系统启动初期   
  54.             // 这时是在做初始化,不应该有冲突发生   
  55.             logger.info("首次验证节点:"  + wsdl);  
  56.             node = MockNodeValidator.validateNode(wsdl);  
  57.             ValidationService.NODE_MAP.put(wsdl, node);  
  58.         }  
  59.         logger.info("节点"  + node.getName() +  "["  + wsdl +  "]验证结束,验证结果:"  + node.getResult());  
  60.         return  node;  
  61.     }  
  62.   
  63.     /**  
  64.      * 将src的内容合并进dest节点中,不进行深度拷贝  
  65.      */   
  66.     private  Node mergeNode(Node src, Node dest) {  
  67.         dest.setName(src.getName());  
  68.         dest.setWsdl(src.getWsdl());  
  69.         dest.setDependencies(src.getDependencies());  
  70.         dest.setResult(src.getResult());  
  71.         return  dest;  
  72.     }  
  73. }  
   

请注意ValidationTask的call()方法,这里会先检查节点是否被锁定,如果被锁定则表示当前有另一个线程正在验证该节点,那就不用重复进行验证。第50行和第51行,那到锁后立即释放,这里只是为了等待验证结束。

 

讲到Lock,就不能不讲Conditon,前者代替了synchronized,而后者则代替了Object对象上的wait()、notify()和notifyAll()方法(Condition中提供了await()、signal()和signalAll()方法),当满足运行条件前挂起线程。Condition是与Lock结合使用的,通过Lock.newCondition()方法能够创建与Lock绑定的Condition实例。JDK的JavaDoc中有一个例子能够很好地说明Condition的用途及用法:

Java代码 
  1. class  BoundedBuffer {  
  2.   final  Lock lock =  new  ReentrantLock();  
  3.   final  Condition notFull  = lock.newCondition();   
  4.   final  Condition notEmpty = lock.newCondition();   
  5.   
  6.   final  Object[] items =  new  Object[ 100 ];  
  7.   int  putptr, takeptr, count;  
  8.   
  9.   public   void  put(Object x)  throws  InterruptedException {  
  10.     lock.lock();  
  11.     try  {  
  12.       while  (count == items.length)   
  13.         notFull.await();  
  14.       items[putptr] = x;   
  15.       if  (++putptr == items.length) putptr =  0 ;  
  16.       ++count;  
  17.       notEmpty.signal();  
  18.     } finally  {  
  19.       lock.unlock();  
  20.     }  
  21.   }  
  22.   
  23.   public  Object take()  throws  InterruptedException {  
  24.     lock.lock();  
  25.     try  {  
  26.       while  (count ==  0 )   
  27.         notEmpty.await();  
  28.       Object x = items[takeptr];   
  29.       if  (++takeptr == items.length) takeptr =  0 ;  
  30.       --count;  
  31.       notFull.signal();  
  32.       return  x;  
  33.     } finally  {  
  34.       lock.unlock();  
  35.     }  
  36.   }   
  37. }  

说到这里,让我解释一下之前的例子里为什么没有选择Condition来等待验证结束。await()方法在调用时当前线程先要获得对应的锁,既然我都拿到锁了,那也就是说验证已经结束了。。。

分享到:
评论

相关推荐

    实战Concurrent

    "实战Concurrent"这一主题主要聚焦于Java中的并发编程,它涉及到多线程、并发容器、同步机制以及性能优化等多个方面。通过深入理解并实践这些概念,开发者可以更好地设计和实现能够充分利用现代多核处理器能力的应用...

    实战Concurrent-BlockQueue

    《实战Concurrent-BlockQueue》 在Java并发编程领域,`Concurrent-BlockQueue`是一个重要的数据结构,它结合了线程安全与高效性能。本文将深入探讨`ConcurrentLinkedQueue`、`ArrayBlockingQueue`以及`...

    Doug Lea, Concurrent Programming in Java Design Principles and Patterns

    2. **线程安全**:讨论了线程安全问题,如数据竞争、死锁、活锁和饥饿,并提供了避免这些问题的策略,如使用synchronized关键字和volatile变量。 3. **并发设计模式**:书中详细阐述了一系列并发设计模式,如生产者...

    使用Java并发编程Concurrent Programming Using Java

    Java平台提供了丰富的API支持并发编程,如`java.util.concurrent`包下的各种类和接口,这些工具可以帮助开发者更高效地管理多线程环境下的任务调度和数据共享问题。 ### Java并发编程基础 #### 1. 多线程基础 - **...

    java并发编程实战源码-concurrent-programming:《Java并发编程实战》源码整理

    《Java并发编程实战》这本书是Java并发编程领域的一本经典之作,它深入浅出地讲解了如何在Java环境中高效、安全地进行多线程编程。源码整理集合`concurrent-programming-master`提供了书中示例代码,对于学习和理解...

    Java 并发编程实战.pdf

    此外,该书可能会对Java中一些新的并发API进行探讨,如java.util.concurrent包下的工具类和接口,例如Executor框架、Future、CompletableFuture、ConcurrentHashMap、Semaphore等。这些工具类和接口在构建大规模并发...

    concurrent-programming:《实战java高并发程序设计》源码整理

    《实战java高并发程序设计》源码整理联系作者十三的java的学习交流QQ群: 881582471 , 658365129(已满)相关文章书籍封面目录第1章走入并行世界1.1何去何从的并行计算1.1.1忘掉那该死的并行1.1.2可怕的现实:摩尔...

    (PDF带目录)《Java 并发编程实战》,java并发实战,并发

    2. **同步机制**:Java中的同步机制包括`synchronized`关键字、`wait()`, `notify()`和`notifyAll()`方法,以及`Lock`接口和相关的实现,如`ReentrantLock`。这些机制用于控制对共享资源的访问,防止数据不一致和竞...

    《java 并发编程实战高清PDF版》

    《Java并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...

    Java并发编程:设计原则与模式(Concurrent.Programming.in.Java)(中英版)

    这本书不仅提供了丰富的理论知识,还介绍了实战中的设计原则和模式,对于Java开发者来说是不可或缺的参考资源。 在Java并发编程领域,理解设计原则至关重要,因为它们指导我们编写高效、安全且可维护的多线程代码。...

    java concurrent in practive

    《Java并发编程实战》还会讨论`java.util.concurrent`包中的高级并发工具,如`ExecutorService`和`Future`,它们可以方便地管理和控制线程池,提高系统的并行处理能力。`CountDownLatch`、`CyclicBarrier`和`...

    实战Java高并发程序设计(高清版)

    2. **并发容器**:Java提供了一系列优化过的并发容器,如`ConcurrentHashMap`、`BlockingQueue`、`CountDownLatch`和`CyclicBarrier`等,这些容器在多线程环境下提供了高效且安全的数据共享机制。 3. **并发设计...

    Concurrent Programming on Windows

    五、实战技巧与理论知识的完美结合 Steve Teixeira,微软Parallel Computing Platform部门的产品单元经理,对本书给予了高度评价。他认为本书既全面覆盖了Windows平台上的并发编程,又实用地介绍了可以直接应用于...

    python爬虫项目实战

    6. **多线程与异步IO**:通过`concurrent.futures`或者`asyncio`库实现多线程或异步爬取,提升爬虫效率。 7. **Scrapy框架应用**:当项目规模扩大时,使用Scrapy框架可以更好地组织代码,处理复杂的爬虫逻辑,如...

    c#多线程编程实战(原书第二版)源码

    《C#多线程编程实战(原书第二版)源码》是一本深入探讨C#中多线程技术的专业书籍,其源码提供了丰富的实践示例,帮助读者掌握并发编程的核心概念和技术。在C#中,多线程是实现高性能、响应式应用程序的关键组成部分...

    Java并发编程实战

    第2章 线程安全性 2.1 什么是线程安全性 2.2 原子性 2.2.1 竞态条件 2.2.2 示例:延迟初始化中的竞态条件 2.2.3 复合操作 2.3 加锁机制 2.3.1 内置锁 2.3.2 重入 2.4 用锁来保护状态 2.5 活跃性与性能 第...

    java并发编程实战高清版pdf

    2. **同步机制**:Java提供了多种同步机制来避免数据竞争,包括`synchronized`关键字、`volatile`关键字以及`java.util.concurrent`包中的锁(如`ReentrantLock`)。理解它们的原理和使用场景至关重要。 3. **锁**...

    jvm调优实战经验

    - **CMS(Concurrent Mark Sweep)GC**:并发标记清除,尽可能减少STW(Stop-The-World)时间,适合响应时间敏感的应用。 - **G1(Garbage-First)GC**:新一代的垃圾回收器,目标是整体暂停时间可预测,适合...

Global site tag (gtag.js) - Google Analytics