java并发编程实战手册第二章2.8与死锁的演示

来源:互联网 发布:淘宝卖家货到付款骗局 编辑:程序博客网 时间:2024/06/08 17:58

话不多数先上代码

  

package cn.fans.chapter2.eight;/** *  * @author fcs * @date 2015-4-15 * 描述:在锁中使用多个条件(multiple Condition) * 说明: */public class FileMock {Object bul;    private String content [] ;  //存储文件的内容  private int index;           //从文件中读取内容的行号  /**   * 使用构造方法生成需要的数据   * @param size   * @param length   */  public FileMock(int size,int length){  content = new String[size];    for(int i =0;i < size;i++){  StringBuffer buffer  = new StringBuffer(length);  for(int j =0 ;j< length;j++){  int numb = (int)Math.random() * 255;  buffer.append((char)numb);  }  content[i] = buffer.toString();  }  index = 0;  }  /**   *    * 作者:fcs   * 描述:如果文件有可以处理的数据行则返回true.如果没有可以处理的数据则返回false   * 说明:   * 返回:   * 参数:   * 时间:2015-4-15   */  public boolean hasMoreLines(){  return index < content.length;  }  /**   *    * 作者:fcs   * 描述:返回属性index指定的行内容,并将index自动增加1   * 说明:   * 返回:   * 参数:   * 时间:2015-4-15   */  public String getLine(){  if(this.hasMoreLines()){  System.out.println("mock: "+(content.length - index));  return content[index++];  }  return null;  }  }

package cn.fans.chapter2.eight;import java.util.LinkedList;import java.util.List;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/** *  * @author fcs * @date 2015-4-16 * 描述:缓冲区 * 说明: */public class Buffer {private LinkedList<String> buffer ; // 存放共享数据private int maxsize;    //存放buffer的长度private ReentrantLock  lock;  //用来对修改buffer的代码进行控制。private Condition lines;    //控制行数的条件private Condition space;    //控制是否有数据的条件boolean pendingLines ;      //表示缓冲区是否有数据的条件public Buffer(int maxsize){this.maxsize = maxsize;buffer  = new LinkedList<String>(); lock  = new ReentrantLock();lines = lock.newCondition();space = lock.newCondition();pendingLines = true;}/** *  * 作者:fcs * 描述:将数据插入缓冲区,当缓冲区满的时候,线程等待,当缓冲区有数据的时候唤醒线程 * 说明: * 返回: * 参数: * 时间:2015-4-15 */public void insert(String line){lock.lock();   //获取锁try {while(buffer.size() == maxsize){space.await();   //缓冲区满的时候等待}buffer.offer(line);System.out.printf("%s inserted Line: %d\n",Thread.currentThread().getName(),buffer.size());lines.signalAll() ;  //缓冲区有数据的时候唤醒} catch (InterruptedException e) {e.printStackTrace();} finally{lock.unlock();  //释放锁}}/** *  * 作者:fcs * 描述:返回缓冲区的第一个字符串,先获取锁,然后检查缓冲区是不是有数据行,如果缓冲区是空的 * 就调用条件lines的await()方法等待缓冲区出现数据。 * 当其他线程调用条件lines的signal()或者signalAll()的时候,该线程唤醒 * 在有数据的时候,get方法获取缓冲区的第一行,并且调用条件space的signalAll()的方法,并且返回这个数据行字符串 * 说明: * 返回: * 参数: * 时间:2015-4-15 */public String get(){String line = null;lock.lock();try {while((buffer.size() == 0) && hasPendingLines()){   //这里当条件是 <span style="font-family: Arial, Helvetica, sans-serif;">buffer.size() == 0) & ||hasPendingLines()就会发生死锁,类型是相互等待对方释放锁。</span>lines.await();}if(hasPendingLines()){line = buffer.poll();System.out.printf("%s LIne readed: %d\n",Thread.currentThread().getName(),buffer.size());    space.signalAll();  }} catch (InterruptedException e) {e.printStackTrace();}finally{lock.unlock();}return line;}/*设置pendingLines的值的,当生产者不再生产新数据行的时候调用该方法*/public void setPendingLines(boolean pendingLines){this.pendingLines = pendingLines;}/*如果有数据行返回true*/public boolean hasPendingLines(){return pendingLines || buffer.size() > 0;}}

package cn.fans.chapter2.eight;import java.util.Random;/** *  * @author fcs * @date 2015-4-15 * 描述:消费者线程 * 说明: */public class Consumer  implements Runnable {private Buffer buffer;public Consumer(Buffer buffer) {super();this.buffer = buffer;}@Overridepublic void run() {while(buffer.hasPendingLines()){String line = buffer.get();processLine(line);}}//休眠10毫秒,模拟数据处理public void processLine(String line){Random random  = new Random();try {Thread.sleep(random.nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}}}

package cn.fans.chapter2.eight;/** *  * @author fcs * @date 2015-4-15 * 描述:生产者线程 * 说明: */public class Producer implements  Runnable{private FileMock fileMock;private Buffer buffer;public Producer(FileMock fileMock, Buffer buffer) {super();this.fileMock = fileMock;this.buffer = buffer;}/** * 用来读取文件中的所有行,并且使用insert方法将数据插入到缓冲区中 * 读完数据后设置pendingLines方法通知缓冲区停止生产更多的行。 */@Overridepublic void run() {buffer.setPendingLines(true);while(fileMock.hasMoreLines()){String line = fileMock.getLine();buffer.insert(line);}buffer.setPendingLines(false);}}

package cn.fans.chapter2.eight;public class Main {public static void main(String[] args) {FileMock  fileMock = new FileMock(100, 10);Buffer buffer = new Buffer(20);Producer  producer = new Producer(fileMock, buffer);Thread pthread = new Thread(producer,"producer");Consumer  consumer [] = new Consumer[3];Thread  cthread [] = new Thread[3];for(int i =0;i< 3;i++){consumer[i] = new Consumer(buffer);cthread[i] = new Thread(consumer[i]);}pthread.start();for(int i =0;i< 3;i++){cthread[i].start();}}}

   
      2.8在锁中使用多个条件(Multiple Condition) ---->生产者--消费者问题,使用锁和Condition条件实现,加入数据缓冲区
        1.一个锁可能关联一个或者多个条件,这些条件通过Condition接口声明,目的是允许线程获取锁并且查看等待的某个条件是否满足,如果不满足
        就挂起直到某个线程唤醒它们。
        
        2.Condition接口提供了挂起线程和唤醒线程的机制。
        3.本节使用一个数据缓冲区当做生产者生产数据的容器,消费者从该缓冲区获得数据。
        4.与锁绑定的所有条件对象都是通过Lock接口声明的newCondition方法创建,返回一个Condition对象。
        5.在使用条件的时候,必须获取该条件绑定的锁,带条件的代码必须在调用Lock对象的lock()方法和unlock()方法之间。
        
        6.Condition接口提供了多个方法用来休眠和唤醒线程。
        线程调用await()方法时,该线程自动释放这个条件绑定的锁,其他某个线程才可以获取这个锁并且执行相同的操作,或者执行这个锁保护的另一个临界区代码
        7.必须在while循环中调用await()方法,在条件成立之前不能离开这个循环,当条件不成立时再次调用该方法。
        
        8.signal()方法用来唤醒在某个条件成立的时候在等待锁的线程,并且该方法与await()方法是成对出现的。
        9.如果调用了一个条件的await()方法,却没有调用signal()方法这个线程将永远休眠。
        10.在本案例中修改while循环的条件将导致死锁。
        
      2.9Condition条件的方法说明
        1.await(long time,TimeUnit unit):该方法将等待一定的时间直到发生以下情况之前,线程一直处于休眠状态
           1.其他某个线程中断当前线程。
           2.其他某个线程调用了将当前线程挂起的条件的signal()方法或者signalAll()方法,就是提前唤醒。
           3.指定的等待时间已经过去,自己自动醒来。
           
           4.通过TimeUnit类的常量指定等待的时间。
           
       2.awaitUninterruptibly():是不可中断的。这个线程将休眠直到其他某个线程调用将它挂起的条件的signal()或者signalAll()方法
     
       3.awaitUnit(Date date)调用该方法的线程休眠和唤醒的时机与方法1相同。
        
        



0 0
原创粉丝点击