Java并发之读写锁Lock和条件阻塞Condition的应用

Java 5中提供了另一种实现线程同步或互斥的机制,即使用LockCondition

Lock比传统线程模型中的synchronized方式更加面向对象,也提供了更多可选择的锁机制。与生活中的锁类似,锁本身也是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须使用同一个Lock对象。锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中。

 

Lock使用示例:


[java]  view plain copy
  1. import java.util.concurrent.locks.Lock;  
  2.  import java.util.concurrent.locks.ReentrantLock;  
  3.    
  4.  // An example of using Lock.  
  5.  public class LockTest {  
  6.    
  7.      public static void main(String[] args) {  
  8.          new LockTest().init();  
  9.    
  10.      }  
  11.    
  12.      private void init() {  
  13.          final Outputer outputer = new Outputer();  
  14.          new Thread(new Runnable() {  
  15.              @Override  
  16.              public void run() {  
  17.                  while (true) {  
  18.                      try {  
  19.                          Thread.sleep(10);  
  20.    
  21.                      } catch(InterruptedException e) {  
  22.                          e.printStackTrace();  
  23.    
  24.                      }  
  25.                      outputer.output("aaaaaaaaaaa");  
  26.    
  27.                  }  
  28.    
  29.    
  30.              }  
  31.    
  32.          }).start();  
  33.    
  34.          new Thread(new Runnable() {  
  35.              @Override  
  36.              public void run() {  
  37.                  while (true) {  
  38.                      try {  
  39.                          Thread.sleep(10);  
  40.    
  41.                      } catch(InterruptedException e) {  
  42.                          e.printStackTrace();  
  43.    
  44.                      }  
  45.                      outputer.output("bbbbbbbbbbb");  
  46.    
  47.                  }  
  48.    
  49.    
  50.              }  
  51.    
  52.          }).start();  
  53.    
  54.    
  55.      }  
  56.    
  57.      static class Outputer {  
  58.          private Lock lock = new ReentrantLock();  
  59.          public void output(String name) {  
  60.              int len = name.length();  
  61.              lock.lock();  
  62.              try {  
  63.                  for (int i = 0; i < len; i++) {  
  64.                      System.out.print(name.charAt(i));  
  65.    
  66.                  }  
  67.                  System.out.println();  
  68.    
  69.              } finally {  
  70.                  lock.unlock();  
  71.    
  72.              }  
  73.    
  74.          }  
  75.    
  76.      }  
  77.    
  78.  }  

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的,我们只需要上好相应的锁即可。如果代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果代码修改数据,只能有一个人在写,并不能同时读取,那就上写销锁。总之,读的时候上读锁,写的时候上写锁。

Java读写锁示例:

[java]  view plain copy
  1. import java.util.Random;  
  2.  import java.util.concurrent.locks.ReadWriteLock;  
  3.  import java.util.concurrent.locks.ReentrantReadWriteLock;  
  4.     
  5.  public class ReadWriteLockTest {  
  6.      public static void main(String[] args) {  
  7.          final MyQueue queue = new MyQueue();  
  8.          for (int i = 0; i < 3; i++) {  
  9.              new Thread() {  
  10.                  public void run() {  
  11.                      while (true) {  
  12.                          queue.get();  
  13.                      }  
  14.                  }  
  15.     
  16.              }.start();  
  17.     
  18.              new Thread() {  
  19.                  public void run() {  
  20.                      while (true) {  
  21.                          queue.put(new Random().nextInt(10000));  
  22.                      }  
  23.                  }  
  24.     
  25.              }.start();  
  26.          }  
  27.     
  28.      }  
  29.  }  
  30.     
  31.  class MyQueue {  
  32.      // 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。  
  33.      private Object data = null;   
  34.      ReadWriteLock  rwl  = new ReentrantReadWriteLock();  
  35.     
  36.      public void get() {  
  37.          rwl.readLock().lock();  
  38.          try {  
  39.              System.out.println(Thread.currentThread().getName()  
  40.                      + " be ready to read data!");  
  41.              Thread.sleep((long) (Math.random() * 1000));  
  42.              System.out.println(Thread.currentThread().getName()  
  43.                      + "have read data :" + data);  
  44.          } catch (InterruptedException e) {  
  45.              e.printStackTrace();  
  46.          } finally {  
  47.              rwl.readLock().unlock();  
  48.          }  
  49.      }  
  50.     
  51.      public void put(Object data) {  
  52.     
  53.          rwl.writeLock().lock();  
  54.          try {  
  55.              System.out.println(Thread.currentThread().getName()  
  56.                      + " be ready to write data!");  
  57.              Thread.sleep((long) (Math.random() * 1000));  
  58.              this.data = data;  
  59.              System.out.println(Thread.currentThread().getName()  
  60.                      + " have write data: " + data);  
  61.          } catch (InterruptedException e) {  
  62.              e.printStackTrace();  
  63.          } finally {  
  64.              rwl.writeLock().unlock();  
  65.          }  
  66.      }  
  67.        
  68.  }  

使用

[java]  view plain copy
  1. import java.util.HashMap;  
  2.  import java.util.Map;  
  3.  import java.util.concurrent.locks.ReadWriteLock;  
  4.  import java.util.concurrent.locks.ReentrantReadWriteLock;  
  5.    
  6.  // Using a ReadWriteLock to implement a cache.  
  7.  public class CacheDemo {  
  8.    
  9.      private Map < String,  
  10.      Object > cache = new HashMap < String,  
  11.      Object > ();  
  12.      private ReadWriteLock rwl = new ReentrantReadWriteLock();  
  13.    
  14.      public static void main(String[] args) {  
  15.          CacheDemo cache = new CacheDemo();  
  16.          Object obj = cache.getData("");  
  17.          System.out.println(obj.toString());  
  18.    
  19.      }  
  20.    
  21.      // Get the value from DB if the value does not exist,and then return it.  
  22.      public Object getData(String key) {  
  23.          rwl.readLock().lock();  
  24.          Object value = null;  
  25.          try {  
  26.              value = cache.get(key);  
  27.              if (value == null) {  
  28.                  // Must release read lock before acquiring write lock  
  29.                  rwl.readLock().unlock();  
  30.                  rwl.writeLock().lock();  
  31.                  try {  
  32.                      // Recheck state because another thread might have acquired  
  33.                      // write lock and changed state before we did.  
  34.                      if (value == null) {  
  35.                          // Here may access Database.  
  36.                          // ...  
  37.                          value = "Data";  
  38.    
  39.                      }  
  40.    
  41.                  } finally {  
  42.                      rwl.writeLock().unlock();  
  43.    
  44.                  }  
  45.                  rwl.readLock().lock();  
  46.    
  47.              }  
  48.    
  49.          } finally {  
  50.              rwl.readLock().unlock();  
  51.    
  52.          }  
  53.          return value;  
  54.    
  55.      }  
  56.    
  57.  }  

Condition的功能类似在传统线程技术中的Object.waitObject.notity的功能。在等待Condition时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

 

一个锁内部可以有多个Condition,即有多路等待和通知,可以参看Jdk1.5提供的LockCondition实现的可阻塞队列的应用案例。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象。

 

JDK文档中提供了一个很不错的示例(http://docs.oracle.com/javase/6/docs/api/ ),用Condition实现一个阻塞队列,代码如下:

[java]  view plain copy
  1. import java.util.concurrent.locks.Condition;  
  2.  import java.util.concurrent.locks.Lock;  
  3.  import java.util.concurrent.locks.ReentrantLock;  
  4.    
  5.  public class BoundedBuffer {  
  6.      final Lock lock = new ReentrantLock();  
  7.      final Condition notFull = lock.newCondition();  
  8.      final Condition notEmpty = lock.newCondition();  
  9.    
  10.      final Object[] items = new Object[100];  
  11.      int putptr,  
  12.      takeptr,  
  13.      count;  
  14.    
  15.      public void put(Object x) throws InterruptedException {  
  16.          lock.lock();  
  17.          try {  
  18.              while (count == items.length)  
  19.              notFull.await();  
  20.              items[putptr] = x;  
  21.              if (++putptr == items.length)  
  22.              putptr = 0;  
  23.              ++count;  
  24.              notEmpty.signal();  
  25.    
  26.          } finally {  
  27.              lock.unlock();  
  28.    
  29.          }  
  30.    
  31.      }  
  32.    
  33.      public Object take() throws InterruptedException {  
  34.          lock.lock();  
  35.          try {  
  36.              while (count == 0)  
  37.              notEmpty.await();  
  38.              Object x = items[takeptr];  
  39.              if (++takeptr == items.length)  
  40.              takeptr = 0;  
  41.              --count;  
  42.              notFull.signal();  
  43.              return x;  
  44.    
  45.          } finally {  
  46.              lock.unlock();  
  47.    
  48.          }  
  49.    
  50.      }  
  51.    
  52.  }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值