Java并发编程实例--19.在一个锁中使用多个条件

一个锁可能关联了一个或多个条件。这些条件可以在Condition接口中声名。

使用这些条件的目的是去控制一个锁并且可以检查一个条件是true或false,如果为false,则暂停直到

另一个线程来唤醒它。

Condition接口提供了这样一个机制 去暂定一个线程和唤醒一个暂停中的线程。

本例中继续拿生产者-消费者问题举例。

FileMock.java

package com.dylan.thread.ch2.c07.utils;

/**
 * This class simulates a text file. It creates a defined number
 * of random lines to process them sequentially.
 *
 */
public class FileMock {
	
	/**
	 * Content of the simulate file
	 */
	private String content[];
	/**
	 * Number of the line we are processing
	 */
	private int index;
	
	/**
	 * Constructor of the class. Generate the random data of the file
	 * @param size: Number of lines in the simulate file
	 * @param length: Length of the lines
	 */
	public FileMock(int size, int length){
		content=new String[size];
		for (int i=0; i<size; i++){
			StringBuilder buffer=new StringBuilder(length);
			for (int j=0; j<length; j++){
				int indice=(int)Math.random()*255;
				buffer.append((char)indice);
			}
			content[i]=buffer.toString();
		}
		index=0;
	}
	
	/**
	 * Returns true if the file has more lines to process or false if not
	 * @return true if the file has more lines to process or false if not
	 */
	public boolean hasMoreLines(){
		return index<content.length;
	}
	
	/**
	 * Returns the next line of the simulate file or null if there aren't more lines
	 * @return
	 */
	public String getLine(){
		if (this.hasMoreLines()) {
			System.out.println("Mock: "+(content.length-index));
			return content[index++];
		} 
		return null;
	}
	
}

Buffer.java

package com.dylan.thread.ch2.c07.task;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * This class implements a buffer to stores the simulate file lines between the
 * producer and the consumers
 * 
 */
public class Buffer {

	/**
	 * The buffer
	 */
	private LinkedList<String> buffer;

	/**
	 * Size of the buffer
	 */
	private int maxSize;

	/**
	 * Lock to control the access to the buffer
	 */
	private ReentrantLock lock;

	/**
	 * Conditions to control that the buffer has lines and has empty space
	 */
	private Condition lines;
	private Condition space;

	/**
	 * Attribute to control where are pending lines in the buffer
	 */
	private boolean pendingLines;

	/**
	 * Constructor of the class. Initialize all the objects
	 * 
	 * @param maxSize
	 *            The size of the buffer
	 */
	public Buffer(int maxSize) {
		this.maxSize = maxSize;
		buffer = new LinkedList<>();
		lock = new ReentrantLock();
		lines = lock.newCondition();
		space = lock.newCondition();
		pendingLines = true;
	}

	/**
	 * Insert a line in the buffer
	 * 
	 * @param line
	 *            line to insert in the buffer
	 */
	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();
		}
	}

	/**
	 * Returns a line from the buffer
	 * 
	 * @return a line from the buffer
	 */
	public String get() {
		String line=null;
		lock.lock();		
		try {
			while ((buffer.size() == 0) &&(hasPendingLines())) {
				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;
	}

	/**
	 * Establish the value of the variable
	 * 
	 * @param pendingLines
	 */
	public void setPendingLines(boolean pendingLines) {
		this.pendingLines = pendingLines;
	}

	/**
	 * Returns the value of the variable
	 * 
	 * @return the value of the variable
	 */
	public boolean hasPendingLines() {
		return pendingLines || buffer.size() > 0;
	}

}

Producer.java

package com.dylan.thread.ch2.c07.task;


import com.dylan.thread.ch2.c07.utils.FileMock;

/**
 * This class gets lines from the simulate file and stores them in the
 * buffer, if there is space in it.
 *
 */
public class Producer implements Runnable {

	/**
	 * Simulated File
	 */
	private FileMock mock;
	
	/**
	 * Buffer
	 */
	private Buffer buffer;
	
	/**
	 * Constructor of the class. Initialize the objects
	 * @param mock Simulated file
	 * @param buffer Buffer
	 */
	public Producer (FileMock mock, Buffer buffer){
		this.mock=mock;
		this.buffer=buffer;	
	}
	
	/**
	 * Core method of the producer. While are pending lines in the
	 * simulated file, reads one and try to store it in the buffer.
	 */
	@Override
	public void run() {
		buffer.setPendingLines(true);
		while (mock.hasMoreLines()){
			String line=mock.getLine();
			buffer.insert(line);
		}
		buffer.setPendingLines(false);
	}

}

Consumer.java

package com.dylan.thread.ch2.c07.task;

import java.util.Random;

/**
 * This class reads line from the buffer and process it
 *
 */
public class Consumer implements Runnable {

	/**
	 * The buffer
	 */
	private Buffer buffer;
	
	/**
	 * Constructor of the class. Initialize the buffer
	 * @param buffer
	 */
	public Consumer (Buffer buffer) {
		this.buffer=buffer;
	}
	
	/**
	 * Core method of the consumer. While there are pending lines in the
	 * buffer, try to read one.
	 */
	@Override
	public void run() {
		while (buffer.hasPendingLines()) {
			String line=buffer.get();
			processLine(line);
		}
	}

	/**
	 * Method that simulates the processing of a line. Waits 10 milliseconds
	 * @param line
	 */
	private void processLine(String line) {
		try {
			Random random=new Random();
			Thread.sleep(random.nextInt(100));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}

}

Main.java

package com.dylan.thread.ch2.c07.core;


import com.dylan.thread.ch2.c07.task.Buffer;
import com.dylan.thread.ch2.c07.task.Consumer;
import com.dylan.thread.ch2.c07.task.Producer;
import com.dylan.thread.ch2.c07.utils.FileMock;

/**
 * Main class of the example
 *
 */
public class Main {

	/**
	 * Main method of the example
	 * @param args
	 */
	public static void main(String[] args) {
		/**
		 * Creates a simulated file with 100 lines
		 */
		FileMock mock=new FileMock(101, 10);
		
		/**
		 * Creates a buffer with a maximum of 20 lines
		 */
		Buffer buffer=new Buffer(20);
		
		/**
		 * Creates a producer and a thread to run it
		 */
		Producer producer=new Producer(mock, buffer);
		Thread threadProducer=new Thread(producer,"Producer");
		
		/**
		 * Creates three consumers and threads to run them
		 */
		Consumer consumers[]=new Consumer[3];
		Thread threadConsumers[]=new Thread[3];
		
		for (int i=0; i<3; i++){
			consumers[i]=new Consumer(buffer);
			threadConsumers[i]=new Thread(consumers[i],"Consumer "+i);
		}
		
		/**
		 * Strats the producer and the consumers
		 */
		threadProducer.start();
		for (int i=0; i<3; i++){
			threadConsumers[i].start();
		}
	}

}

运行结果:

Mock: 101
Producer: Inserted Line: 1
Mock: 100
Producer: Inserted Line: 2
Mock: 99
Producer: Inserted Line: 3
Mock: 98
Producer: Inserted Line: 4
Mock: 97
Producer: Inserted Line: 5
Mock: 96
Producer: Inserted Line: 6
Mock: 95
Producer: Inserted Line: 7
Mock: 94
Producer: Inserted Line: 8
Mock: 93
Producer: Inserted Line: 9
Mock: 92
Producer: Inserted Line: 10
Mock: 91
Producer: Inserted Line: 11
Mock: 90
Producer: Inserted Line: 12
Mock: 89
Producer: Inserted Line: 13
Mock: 88
Producer: Inserted Line: 14
Mock: 87
Producer: Inserted Line: 15
Mock: 86
Producer: Inserted Line: 16
Mock: 85
Producer: Inserted Line: 17
Mock: 84
Producer: Inserted Line: 18
Mock: 83
Producer: Inserted Line: 19
Mock: 82
Producer: Inserted Line: 20
Mock: 81
Consumer 0: Line Readed: 19
Consumer 0: Line Readed: 18
Consumer 1: Line Readed: 17

Mock: 2
Consumer 1: Line Readed: 19
Consumer 2: Line Readed: 18
Consumer 2: Line Readed: 17
Producer: Inserted Line: 18
Mock: 1
Producer: Inserted Line: 19
Consumer 0: Line Readed: 18
Consumer 2: Line Readed: 17
Consumer 1: Line Readed: 16
Consumer 0: Line Readed: 15
Consumer 2: Line Readed: 14
Consumer 0: Line Readed: 13
Consumer 2: Line Readed: 12
Consumer 1: Line Readed: 11
Consumer 0: Line Readed: 10
Consumer 0: Line Readed: 9
Consumer 2: Line Readed: 8
Consumer 0: Line Readed: 7
Consumer 2: Line Readed: 6
Consumer 1: Line Readed: 5
Consumer 1: Line Readed: 4
Consumer 0: Line Readed: 3
Consumer 2: Line Readed: 2
Consumer 0: Line Readed: 1
Consumer 1: Line Readed: 0





    原文作者:java锁
    原文地址: https://blog.csdn.net/IndexMan/article/details/80330899
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞