A lock may be associated with one or more conditions.
These conditions are declared in the Condition
interface.
import java.util.LinkedList; import java.util.Random; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Main { public static void main(String[] args) { ContentReader contentReader = new ContentReader(101, 10); Buffer buffer = new Buffer(20); Thread threadProducer = new Thread(new Producer(contentReader, buffer), "Producer"); Thread threadConsumers[] = new Thread[3]; for (int i = 0; i < 3; i++) { threadConsumers[i] = new Thread(new Consumer(buffer), "Consumer " + i); }//from ww w .j ava 2s .c o m threadProducer.start(); for (int i = 0; i < 3; i++) { threadConsumers[i].start(); } } } class Buffer { private LinkedList<String> buffer = new LinkedList<>(); private int maxSize; private ReentrantLock lock = new ReentrantLock(); private Condition lines = lock.newCondition(); private Condition space; private boolean pendingLines = true; public Buffer(int maxSize) { this.maxSize = maxSize; space = lock.newCondition(); } 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(); } } 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; } public void setPendingLines(boolean pendingLines) { this.pendingLines = pendingLines; } public boolean hasPendingLines() { return pendingLines || buffer.size() > 0; } } class Consumer implements Runnable { private Buffer buffer; public Consumer(Buffer buffer) { this.buffer = buffer; } @Override public void run() { while (buffer.hasPendingLines()) { String line = buffer.get(); processLine(line); } } private void processLine(String line) { try { Random random = new Random(); Thread.sleep(random.nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } } } class Producer implements Runnable { private ContentReader contentReader; private Buffer buffer; public Producer(ContentReader c, Buffer buffer) { this.contentReader = c; this.buffer = buffer; } @Override public void run() { buffer.setPendingLines(true); while (contentReader.hasMoreLines()) { String line = contentReader.getLine(); buffer.insert(line); } buffer.setPendingLines(false); } } class ContentReader { private String content[]; private int index; public ContentReader(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; } public boolean hasMoreLines() { return index < content.length; } public String getLine() { if (this.hasMoreLines()) { System.out.println("Mock: " + (content.length - index)); return content[index++]; } return null; } }