发编程包的java.util.concurrent.locks

并发编程包的java.util.concurrent.locks包下。这里提供了一些对多线程进行互斥同步控制的类,用以取代之前我们一直使用的synchronized关键字,wait()、notify()、notifyAll()方法。

【Lock】

Lock是一个接口,和关键字synchronized的功能一致,对多线程进行互斥控制!其使用更加面向对象化!对互斥代码段的控制也更加精细化!Lock接口有三个实现类:ReentrantLock,ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock。后两者都是ReentrantReadWriteLock的子类,这个我们后面再讲。这里先看一个ReentrantLock的例子:

  1. package cn.test;  
  2.   
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5.   
  6. public class ReentrantLockTest {  
  7.   
  8.     Lock lock = new ReentrantLock();  
  9.     /** 
  10.      * 业务方法,需要进行并发互斥控制!我们此处不使用synchronized关键字 
  11.      */  
  12.     public void doBisiness(){  
  13.           
  14.         // 加锁,加锁成功的线程进入执行,不成功的线程阻塞在这里!  
  15.         lock.lock();  
  16.         try{  
  17.             // 相应的业务处理方法  
  18.               
  19.         }catch(Exception e){  
  20.               
  21.               
  22.         }finally{  
  23.               
  24.             // 释放锁,为防止业务方法处理有异常抛出,通常将释放锁的代码写到finally块中  
  25.             lock.unlock();  
  26.         }  
  27.           
  28.     }  
  29. }  

这次加锁的过程就是调用一个对象的方法!感觉很舒服,比synchronized更易用并且容易理解!

【ReadWriteLock】

ReadWriteLock也是一个接口,用来实现读写锁的概念(在synchronized的时代,这个是不被支持的)。读写锁的概念,就是读锁与读锁之间不互斥,读锁与写锁,写锁和写锁之间互斥!这种加锁模式,在某些情况下能提高效率!ReentrantReadWriteLock是ReadWriteLock接口的唯一个实现类。其内部提供了两个子类,ReadLock,WriteLock分别来提供读锁和写锁的功能!我们看一个缓存系统的例子,我们需要一个并发环境下的缓存系统,可以缓存多个对象,要求稳定并且性能高效:

  1. package cn.test;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5. import java.util.concurrent.locks.ReadWriteLock;  
  6. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  7.   
  8. public class CacheDemo {  
  9.       
  10.     // 将缓存系统设计为单例  
  11.     private static final CacheDemo INSTANCE = new CacheDemo();  
  12.     // 内部通过Map的形式来缓存数据  
  13.     private Map<String, Object> cacheMap = new HashMap<String, Object>();  
  14.     // 并发互斥通过读写锁进行  
  15.     private ReadWriteLock lock = new ReentrantReadWriteLock();  
  16.     private CacheDemo(){  
  17.           
  18.     }  
  19.     public static CacheDemo getInstance(){  
  20.           
  21.         return INSTANCE;  
  22.     }  
  23.       
  24.     /** 
  25.      * 添加缓存的方法,这里是覆盖式添加! 
  26.      * @param key 
  27.      * @param value 
  28.      */  
  29.     public void put(String key, Object value){  
  30.           
  31.         // 加写锁  
  32.         lock.writeLock().lock();  
  33.         try{  
  34.               
  35.             cacheMap.put(key, value);  
  36.         }finally{  
  37.               
  38.             lock.writeLock().unlock();  
  39.         }  
  40.     }  
  41.       
  42.     /** 
  43.      * 从缓存中读取数据,使用读锁即可,多个线程可以同时从缓存中读取数据! 
  44.      * @param key 
  45.      * @return 
  46.      */  
  47.     public Object get(String key){  
  48.           
  49.         // 局部变量,无需进行并发互斥控制  
  50.         Object value = null;  
  51.         // 加读锁  
  52.         lock.readLock().lock();  
  53.         try{  
  54.               
  55.             value = cacheMap.get(key);  
  56.         }finally{  
  57.               
  58.             lock.readLock().unlock();  
  59.         }  
  60.         return value;  
  61.     }  
  62.       
  63.     /** 
  64.      * 从缓存中移出数据!需要使用写锁! 
  65.      * @param key 
  66.      * @return 
  67.      */  
  68.     public boolean remove(String key){  
  69.           
  70.         boolean result = true;  
  71.         // 删除缓存,加写锁  
  72.         lock.writeLock().lock();  
  73.         try{  
  74.               
  75.             cacheMap.remove(key);  
  76.         }catch(Exception e){  
  77.               
  78.             result = false;  
  79.         }finally{  
  80.               
  81.             lock.writeLock().unlock();  
  82.         }  
  83.           
  84.         return result;  
  85.           
  86.     }  
  87.       
  88.   
  89. }  

利用读写锁实现的缓存效率比利用ReentrantLock或synchronized(可以认为也就是一个写锁关键字)实现的缓存要高!因为这个缓存支持多个线程并发读取!以后当我们在实际情况中,遇到过在读写同时存在的情况下,需要进行并发控制,我们就要考虑到使用读写锁!关于读写锁,再提一点,读写锁有个特性,就是线程如果持有读锁,想升级获取写锁,就必须先释放读锁,再去申请写锁。如果线程持有写锁,可以在持有写锁的情况下,再申请一个读锁,然后再释放写锁!

http://my.oschina.net/sharkbobo/blog/270188 --使用ReentrantReadWriteLock进行线程通信

【Condition】

Condition可以用来实现wait、notify、notifyAll方法的线程间同步通信。但其有增强的地方。我们先看一下wait等方法的使用情况:我们先得到一个对象的监视器,进入同步代码块,发现有些条件限制,我们的线程就要wait在这个对象监视器上,如果我们有100个线程,这100条线程有可能会因为不同的条件限制而要wait,但结果是他们都wait在同一个对象监视器上。一旦有另一个线程处理完了某种条件限制,这种限制的解除会让这100条线程中的5条可以继续执行,但这个线程无法通过notify去精确通知这5条线程,他只能调用notifyAll,去通知所有线程,然后其中95条再重新获取到对象监视器后发现不得不继续wait!!这是wait等方法低效的地方,Condition就对这种情况进行了很好的改进!在使用同一个锁进行互斥控制的线程,可以在不同的Condition对象上进行等待和被唤醒!这就是"多路Condition"的概念!

我们看个这方面的例子,有4条线程,老大,老二,老三,老四,最后实现的效果是:老大执行10次,接着老二再执行20次,接着老三再执行30次,接着老四再执行40次,再循环回去,进行10遍!这里涉及到了顺序执行的问题,我们就利用多路Condition进行精确控制:

  1. package cn.test;  
  2.   
  3. import java.util.concurrent.locks.Condition;  
  4. import java.util.concurrent.locks.Lock;  
  5. import java.util.concurrent.locks.ReentrantLock;  
  6.   
  7. public class MultiConditionsTest {  
  8.   
  9.     public static void main(String[] args) {  
  10.           
  11.         final Task task = new Task();  
  12.         // 启动四个线程,分别执行任务类中的4个任务!  
  13.         new Thread(new Runnable(){  
  14.             @Override  
  15.             public void run() {  
  16.                 for(int j=0;j<10;j++){  
  17.                     task.output1();  
  18.                 }  
  19.             }}, "First Thread").start();  
  20.         new Thread(new Runnable(){  
  21.             @Override  
  22.             public void run() {  
  23.                 for(int j=0;j<10;j++){  
  24.                     task.output2();  
  25.                 }  
  26.             }}, "Second Thread").start();  
  27.         new Thread(new Runnable(){  
  28.             @Override  
  29.             public void run() {  
  30.                 for(int j=0;j<10;j++){  
  31.                     task.output3();  
  32.                 }  
  33.             }}, "Third Thread").start();  
  34.         new Thread(new Runnable(){  
  35.             @Override  
  36.             public void run() {  
  37.                 for(int j=0;j<10;j++){  
  38.                     task.output4();  
  39.                 }  
  40.             }}, "Forth Thread").start();  
  41.     }  
  42.   
  43.     private static class Task {  
  44.   
  45.         private int ctrlOrder = 0;  
  46.         // 创建一个互斥控制的锁  
  47.         private Lock lock = new ReentrantLock();  
  48.         // 调用锁的newCondtion方法,得到一个Condtion对象!  
  49.         private Condition op1Condition = lock.newCondition();  
  50.         private Condition op2Condition = lock.newCondition();  
  51.         private Condition op3Condition = lock.newCondition();  
  52.         private Condition op4Condition = lock.newCondition();  
  53.   
  54.         public void output1() {  
  55.   
  56.             lock.lock();  
  57.             try {  
  58.   
  59.                 // 使用Condition也会产生假醒现象!所以此处要用while循环进行判断!  
  60.                 while (ctrlOrder % 4 != 0) {  
  61.   
  62.                     // 调用Condtion对象的await方法,进行等待  
  63.                     op1Condition.await();  
  64.                 }  
  65.                 // 执行相应的业务逻辑  
  66.                 for (int i = 0; i < 10; i++) {  
  67.   
  68.                     System.out.println(Thread.currentThread().getName()  
  69.                             + " out put " + i);  
  70.                 }  
  71.                 ctrlOrder++;  
  72.                 // 通过调用特定的Condition的signal来唤醒在该Condition对象上等待的线程!精确唤醒!  
  73.                 op2Condition.signal();  
  74.             } catch (InterruptedException e) {  
  75.                 e.printStackTrace();  
  76.             } finally {  
  77.   
  78.                 lock.unlock();  
  79.             }  
  80.         }  
  81.   
  82.         public void output2() {  
  83.   
  84.             lock.lock();  
  85.             try {  
  86.   
  87.                 // 使用Condition也会产生假醒现象!所以此处要用while循环进行判断!  
  88.                 while (ctrlOrder % 4 != 1) {  
  89.   
  90.                     // 调用Condtion对象的await方法,进行等待  
  91.                     op2Condition.await();  
  92.                 }  
  93.                 // 执行相应的业务逻辑  
  94.                 for (int i = 0; i < 20; i++) {  
  95.   
  96.                     System.out.println(Thread.currentThread().getName()  
  97.                             + " out put " + i);  
  98.                 }  
  99.                 ctrlOrder++;  
  100.                 // 通过调用特定的Condition的signal来唤醒在该Condition对象上等待的线程!精确唤醒!  
  101.                 op3Condition.signal();  
  102.             } catch (InterruptedException e) {  
  103.                 e.printStackTrace();  
  104.             } finally {  
  105.   
  106.                 lock.unlock();  
  107.             }  
  108.         }  
  109.   
  110.         public void output3() {  
  111.   
  112.             lock.lock();  
  113.             try {  
  114.   
  115.                 // 使用Condition也会产生假醒现象!所以此处要用while循环进行判断!  
  116.                 while (ctrlOrder % 4 != 2) {  
  117.   
  118.                     // 调用Condtion对象的await方法,进行等待  
  119.                     op3Condition.await();  
  120.                 }  
  121.                 // 执行相应的业务逻辑  
  122.                 for (int i = 0; i < 30; i++) {  
  123.   
  124.                     System.out.println(Thread.currentThread().getName()  
  125.                             + " out put " + i);  
  126.                 }  
  127.                 ctrlOrder++;  
  128.                 // 通过调用特定的Condition的signal来唤醒在该Condition对象上等待的线程!精确唤醒!  
  129.                 op4Condition.signal();  
  130.             } catch (InterruptedException e) {  
  131.                 e.printStackTrace();  
  132.             } finally {  
  133.   
  134.                 lock.unlock();  
  135.             }  
  136.         }  
  137.   
  138.         public void output4() {  
  139.   
  140.             lock.lock();  
  141.             try {  
  142.   
  143.                 // 使用Condition也会产生假醒现象!所以此处要用while循环进行判断!  
  144.                 while (ctrlOrder % 4 != 3) {  
  145.   
  146.                     // 调用Condtion对象的await方法,进行等待  
  147.                     op4Condition.await();  
  148.                 }  
  149.                 // 执行相应的业务逻辑  
  150.                 for (int i = 0; i < 40; i++) {  
  151.   
  152.                     System.out.println(Thread.currentThread().getName()  
  153.                             + " out put " + i);  
  154.                 }  
  155.                 ctrlOrder++;  
  156.                 // 通过调用特定的Condition的signal来唤醒在该Condition对象上等待的线程!精确唤醒!  
  157.                 op1Condition.signal();  
  158.             } catch (InterruptedException e) {  
  159.                 e.printStackTrace();  
  160.             } finally {  
  161.   
  162.                 lock.unlock();  
  163.             }  
  164.         }  
  165.   
  166.     }  
  167.   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值