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

话不多数先上代码

  

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;
	}

	@Override
	public 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方法通知缓冲区停止生产更多的行。
	 */
	@Override
	public 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相同。
        
        



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值