zoukankan      html  css  js  c++  java
  • ReentrantLock与Condition构造有界缓存队列与数据栈

    通过ReentrantLock与Condition的设计,以数组为基础,可以实现简单的队列和栈的数据结构,临界阻塞的效果。

    ReentrantLock相对于synchronized比较大的一个区别是有条件变量:Condition,很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。Condition(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。多个Condition需要绑定到同一锁上,可以实现队列与栈。

    队列:先进先出的原则

    栈:先进后出的原则

    类一:模拟队列的读写操作

      1 package reentranlock;
      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 BoundedBufferQueue {
      8 
      9     static Lock lock = new ReentrantLock();
     10     static Condition read = lock.newCondition();
     11     static Condition write = lock.newCondition();
     12     static Object [] data = new Object [10];// 构造一个缓存队列
     13     
     14     private static int count = 0;// 用来标识队列中存放的数据量
     15     private static int readIndex = 0;// 标识读取的下标
     16     private static int writeIndex = 0;// 标识写入的下标
     17     
     18     public static void put(Integer num) throws InterruptedException {
     19         try {
     20             lock.lock();
     21             if (count == 10) {
     22                 write.await();// 数据量满了则阻塞写的操作
     23             }
     24             data[writeIndex] = num;
     25             count++;
     26             if (++writeIndex == 10) {// 循环写入数据
     27                 writeIndex = 0;
     28             }
     29             read.signal();// 触发读操作
     30         } finally {
     31             lock.unlock();
     32         }
     33     }
     34     
     35     public static Object take() throws InterruptedException {
     36         Object result = null;
     37         try {
     38             lock.lock();
     39             if (count == 0) {// 如果队列无数据量则阻塞读操作
     40                 read.await();
     41             }
     42             result = (Integer) data[readIndex];
     43             count--;
     44             if (++readIndex == 10) {// 循环取数据
     45                 readIndex = 0;
     46             }
     47             write.signal();// 触发写操作
     48         } finally {
     49             lock.unlock();
     50         }
     51         return result;
     52     }
     53     
     54     // 下面是模拟读写操作过程,可以通过操作时间不同来验证队列读取。
     55     public static void main(String[] args) throws InterruptedException {
     56         
     57         Runnable readThread = new Runnable() {
     58             @Override
     59             public void run() {
     60                 while(true){
     61                     for(int i=1;i<Integer.MAX_VALUE;i++){
     62                         try {
     63                             Integer o = (Integer) take();
     64                             System.out.println("读取:"+o);
     65                             Thread.sleep(3000);
     66                         } catch (InterruptedException e) {
     67                             e.printStackTrace();
     68                         }
     69                     }
     70                 }
     71                 
     72             }
     73         };
     74         
     75         Runnable writeThread = new Runnable() {
     76             @Override
     77             public void run() {
     78                 while(true){
     79                     for(int i=1;i<Integer.MAX_VALUE;i++){
     80                         try {
     81                             put(i);
     82                             System.out.println("写入:"+i);
     83                             Thread.sleep(1000);
     84                         } catch (InterruptedException e) {
     85                             e.printStackTrace();
     86                         }
     87                     }
     88                 }
     89                 
     90             }
     91         };
     92 
     93         Thread read = new Thread(readThread);
     94         Thread write = new Thread(writeThread);
     95         
     96         read.start();
     97         Thread.currentThread().join(1000);
     98         write.start();
     99     }
    100 
    101 }

    类二:模拟栈的读写操作

      1 package reentranlock;
      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 BoundedBufferStack {
      8 
      9     static Lock lock = new ReentrantLock();
     10     static Condition read = lock.newCondition();
     11     static Condition write = lock.newCondition();
     12     static Object [] data = new Object [10];// 构造一个缓存栈
     13     
     14     private static int count = 0;// 用来标识栈中存放的数据量
     15     private static int index = 0;// 标识的下标
     16     
     17     public static void put(Integer num) throws InterruptedException {
     18         try {
     19             lock.lock();
     20             if (count == 10) {// 数据量满了则阻塞写操作
     21                 write.await();
     22             }
     23             data[index] = num;
     24             count++;
     25             index++;
     26             if (index == 10) {
     27                 index = 0;
     28             }
     29             read.signal();// 触发读操作
     30         } finally {
     31             lock.unlock();
     32         }
     33     }
     34     
     35     public static Object take() throws InterruptedException {
     36         Object result = null;
     37         try {
     38             lock.lock();
     39             if (count == 0) {// 数据量为空则阻塞读操作
     40                 read.await();
     41             }
     42             if(index == 0 && count == 10){// 为了仿造栈的后进先出的模式,取最后写入的数据
     43                 index = 9;
     44             }else{
     45                 index --;
     46             }
     47             result = (Integer) data[index];
     48             count--;
     49             if (index == 0) {
     50                 index = 0;
     51             }
     52             write.signal();// 触发写操作
     53         } finally {
     54             lock.unlock();
     55         }
     56         return result;
     57     }
     58     
     59     // 下面是模拟读写操作过程,可以通过操作时间不同来验证栈的读取。
     60     public static void main(String[] args) throws InterruptedException {
     61         
     62         Runnable readThread = new Runnable() {
     63             @Override
     64             public void run() {
     65                 while(true){
     66                     for(int i=1;i<Integer.MAX_VALUE;i++){
     67                         try {
     68                             Integer o = (Integer) take();
     69                             System.out.println("读取:"+o);
     70                             Thread.sleep(5000);
     71                         } catch (InterruptedException e) {
     72                             e.printStackTrace();
     73                         }
     74                     }
     75                 }
     76                 
     77             }
     78         };
     79         
     80         Runnable writeThread = new Runnable() {
     81             @Override
     82             public void run() {
     83                 while(true){
     84                     for(int i=1;i<Integer.MAX_VALUE;i++){
     85                         try {
     86                             put(i);
     87                             System.out.println("写入:"+i);
     88                             Thread.sleep(1000);
     89                         } catch (InterruptedException e) {
     90                             e.printStackTrace();
     91                         }
     92                     }
     93                 }
     94                 
     95             }
     96         };
     97 
     98         Thread read = new Thread(readThread);
     99         Thread write = new Thread(writeThread);
    100         
    101         write.start();
    102         Thread.currentThread().join(1000);
    103         read.start();
    104     }
    105 
    106 }

     ArrayBlockingQueue也是这种设计 "通过平衡生产者和消费者的处理能力来提高整体处理数据的速度",只不过运用ArrayBlockingQueue不要担心非单一生产者/消费者场景下的系统假死问题,缓冲区空、缓冲区满的场景BlockingQueue都是定义了不同的Condition,所以不会唤醒自己的同类。

  • 相关阅读:
    Log4Net记录到MySql
    创建快照
    grep的用法(CentOS7)及有关正则表达式的使用
    samba
    mkdir
    raid0和raid5的 实验过程
    route
    source和sh执行脚本时的差异
    echo命令的简单用法和实例
    smbpasswd和pdbedit
  • 原文地址:https://www.cnblogs.com/hupu-jr/p/7762477.html
Copyright © 2011-2022 走看看