/* Code of Figure 14.6, pages 641-642 from Kenneth C. Louden, Programming Languages Principles and Practice 2nd Edition Copyright (C) Brooks-Cole/ITP, 2003 */ import java.io.*; class BoundedBuffer { public static void main(String[] args) { Buffer buffer = new Buffer(5); // buffer has size 5 Producer prod = new Producer(buffer); Consumer cons = new Consumer(buffer); Thread read = new Thread(prod); Thread write = new Thread(cons); read.start(); write.start(); try { read.join(); write.interrupt(); } catch (InterruptedException e) {} } } class Buffer { private final char[] buf; private int start = -1; private int end = -1; private int size = 0; public Buffer(int length) { buf = new char[length]; } public boolean more() { return size > 0; } public synchronized void put(char ch) { try { while (size == buf.length) wait(); end = (end+1) % buf.length; buf[end] = ch; size++; notifyAll(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public synchronized char get() { try { while (size == 0) wait(); start = (start+1) % buf.length; char ch = buf[start]; size--; notifyAll(); return ch; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return 0; } } class Consumer implements Runnable { private final Buffer buffer; public Consumer(Buffer b) { buffer = b; } public void run() { while (!Thread.currentThread().isInterrupted()) { char c = buffer.get(); System.out.print(c); } while(buffer.more()) // clean-up { char c = buffer.get(); System.out.print(c); } } } class Producer implements Runnable { private final Buffer buffer; private final InputStreamReader in = new InputStreamReader(System.in); public Producer(Buffer b) { buffer = b; } public void run() { try { while (!Thread.currentThread().isInterrupted()) { int c = in.read(); if (c == -1) break; // -1 is end of file buffer.put((char)c); } } catch (IOException e) {} } }