Using a PipedReader and PipedWriter

A pipe is a communication channel between two threads. It is typically used in producer-consumer systems where one thread produces data (producer) necessary for the other thread (consumer) to operate. In Java, a pipe is implemented by connecting a PipedReader instance to a PipedWriter instance:

   PipedWriter producer = new PipedWriter();
   PipedReader consumer = new PipedReader(producer);

All data written to producer will be stored in a pipe (buffer) until the consumer reads it.

In this example, a thread mimics the behavior of scores for 10 contestants coming in by generating random numbers between [0, 10[. Another thread keeps track of the total votes per contestant.

Main.java:

import java.util.*;
import java.io.*;
 
public class Main {   
   public static void main(String[] args) throws Exception {
      PipedWriter producer = new PipedWriter();
      PipedReader consumer = new PipedReader(producer);
 
      NumberProducer np = new NumberProducer(producer);
      NumberConsumer nc = new NumberConsumer(consumer);
 
      np.start();
      nc.start();
   }
}
 
class NumberProducer extends Thread
{
   BufferedWriter bw;
 
   public NumberProducer(Writer w) {
      this.bw = new BufferedWriter(w);
   }
 
   // thread continually produces random votes
   public void run() {
      try {
         Random r = new Random();
         while (true) {
            String vote = "" + Math.abs((r.nextInt() % 10));
 
            bw.write(vote);
            bw.newLine();
            bw.flush();
 
            sleep(10);
         }  
      }   
      catch(IOException e) {
         System.err.println(e);
      }
      catch(InterruptedException e) {
         System.err.println(e);
      }      
   }
}
 
class NumberConsumer extends Thread
{
   BufferedReader br;
   int[] votes = new int[10];
  
   public NumberConsumer(Reader r) {
      br = new BufferedReader(r);
   }
 
   public void run() {
      try {
         String line;
         int count = 0;
         while ((line = br.readLine()) != null) {
            int contestant = Integer.parseInt(line);
            votes[contestant]++;
 
            count++;
            if (count % 100 == 0) 
               printVotes();
         }      
      }   
      catch(IOException e) {
         System.err.println(e);
      }
   }
 
   public void printVotes() {
      for (int i=0; i<votes.length; i++) {
         System.out.println("Contestant #" + i + ": " + votes[i]);
      }
      System.out.println("——————");
   }
}

outputs:

Contestant #0: 7
Contestant #1: 8
Contestant #2: 10
Contestant #3: 15
Contestant #4: 5
Contestant #5: 11
Contestant #6: 4
Contestant #7: 15
Contestant #8: 16
Contestant #9: 9
------------------
Contestant #0: 22
Contestant #1: 22
Contestant #2: 26
Contestant #3: 21
Contestant #4: 11
Contestant #5: 18
Contestant #6: 13
Contestant #7: 26
Contestant #8: 26
Contestant #9: 15
------------------
Contestant #0: 32
Contestant #1: 29
Contestant #2: 37
Contestant #3: 30
Contestant #4: 29
Contestant #5: 31
Contestant #6: 22
Contestant #7: 35
Contestant #8: 34
Contestant #9: 21
------------------
. . .