Threads: a few examples.

Nicholas Duchon, Mar 30, 2011; Oct 4, 2015.

Outline:



Note Summary:


Polling:

// File: OnOffA.java
// Date: Mar 29, 2011
// Author: Nicholas Duchon
// Purpose: use JButton to turn a thread on and off
//     Shows the polling approach
//     Thread.sleep and goFlag

   import javax.swing.JFrame;
   import javax.swing.JButton;
   import javax.swing.JTextField;
   import javax.swing.JPanel;

   import java.awt.GridLayout;
   import java.awt.BorderLayout;

   import java.awt.event.ActionListener;
   import java.awt.event.ActionEvent;

   public class OnOffA
   extends JFrame
   implements ActionListener, Runnable
   {

      static final long serialVersionUID = 7046131319439923770L;
      JButton jbg = new JButton ("Go");
      JButton jbq = new JButton ("Quit");
      JTextField jt = new JTextField ();
      boolean goFlag = false;
      int count = 0;
      Thread tr = new Thread (this);
      long delay = 200L; // thread polling delay
  
      public OnOffA (String t) {
         setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
         setTitle (t);
         setLocationRelativeTo (null);
         setSize (250, 60);
         setVisible (true);
        
         JPanel jp = new JPanel ();
         jp.setLayout (new GridLayout (1, 3));
         jp.add (jbg);
         jp.add (jt);
         jp.add (jbq);
        
         jt.setHorizontalAlignment (JTextField.RIGHT);
        
         add (jp, BorderLayout.CENTER);
        
         jbg.addActionListener (this);
         jbq.addActionListener (
               new ActionListener () {
                  public void actionPerformed (ActionEvent e) {
                     System.exit(0);}
               });
              
         tr.start ();
      } // end String constructor
  
       public void run () {
         while (true) {
            try {
               if (goFlag)
                  jt.setText (String.format ("%d", count++));
               Thread.sleep (100);
            }
               catch (InterruptedException e) {
               }
         } // end run forever
     
} // end method run
  
      public void actionPerformed (ActionEvent e) {
         if (goFlag) {
            goFlag = false;
            jbg.setText ("Go");
         }
         else {
            goFlag = true;
            jbg.setText ("Stop");
         }
     
} // end method action Performed
  
      public static void main (String args []) {
         new OnOffA ("OnOffA Example");
     
} // end method main 
  
  
} // end class OnOffA

WaitNotify problem: IllegalMonitorStateException

// File: OnOffB.java
// Date: Mar 30, 2011
// Author: Nicholas Duchon
// Purpose: use JButton to turn a thread on and off
//     Trys wait/notify approach
//     But: IllegalMonitorStateException
//     See: OnOffC.java for solution
//     Only sleep if goFlag true

   import javax.swing.JFrame;
   import javax.swing.JButton;
   import javax.swing.JTextField;
   import javax.swing.JPanel;

   import java.awt.GridLayout;
   import java.awt.BorderLayout;

   import java.awt.event.ActionListener;
   import java.awt.event.ActionEvent;

   public class OnOffB
   extends JPanel
   implements Runnable, ActionListener
   {

      static final long serialVersionUID = 7046131319439923771L;
      JButton    jbg    = new JButton ("Go");  // listener and constructor need to access this variable
      JTextField jt     = new JTextField ();   // constructor and run need to access this variable
      boolean    goFlag = false;               // run and listener need to access this variable
      long       delay  = 200L;                // thread polling delay
  
      public OnOffB () {
         setLayout (new GridLayout (1, 0));
         add (jbg);
         add (jt);
        
         jt.setHorizontalAlignment (JTextField.RIGHT);
        
         jbg.addActionListener (this);
              
         Thread tr = new Thread (this);
         tr.start ();
     
} // end String constructor
  
      public void actionPerformed (ActionEvent e) {
         if (goFlag) {
            goFlag = false;
            jbg.setText ("Go");
         }
         else {
            goFlag = true;
            jbg.setText ("Stop");
            notify ();
         }
     
} // end method action Performed
     
      public void run () {
         int count = 0;
         while (true) {
            try {
               if (goFlag) {
                  jt.setText (String.format ("%d", count++));
                  Thread.sleep (delay);
                }
                else
                  wait ();
            }
               catch (InterruptedException e) {
               }
         } // end run forever
     
} // end method run
     
      static JFrame createFrame (String t) {
         JFrame jf = new JFrame (t);
         jf.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
         jf.setLayout (new GridLayout (0, 1));
         jf.setLocationRelativeTo (null);
         jf.setSize (250, 180);
         jf.setVisible (true);
     
         JButton jbq = new JButton ("Quit");
         jf.add (jbq);
         jbq.addActionListener (
               new ActionListener () {
                  public void actionPerformed (ActionEvent e) {
                     System.exit(0);}
               });
     
         return jf;
     
} // end createFrame
  
      public static void main (String args []) {
         JFrame jf = createFrame ("An example");
         jf.add (new OnOffB ());
         jf.add (new OnOffB ());
         jf.add (new OnOffB ());
         jf.add (new OnOffB ());
         jf.add (new OnOffB ());
         jf.validate (); // keep frame size, layout the panels and buttons inside
      } // end method main 
  
  
} // end class OnOffB

Corrected:

Here is a screen shot - note that we have 5 threads set up in this example, each controlled by its own JButton:


// File: OnOffC.java
// Date: Mar 30, 2011
// Author: Nicholas Duchon
// Purpose: use JButton to turn a thread on and off
//     Trys wait/notify approach
//     Added sychronized (this) share the monitor for this instance of the OnOffC JPanel
//        this monitor is shared between the event processing thread and
//        the explicit thread created for this instance of OnOffC
//     Only sleep if goFlag true
// Println inside run/sychronized confirms when thread awakes and checks.
//   Note that synchronized needs an explicit instance as a parameter, here the parameter is "this"

   import javax.swing.JFrame;
   import javax.swing.JButton;
   import javax.swing.JTextField;
   import javax.swing.JPanel;

   import java.awt.GridLayout;
   import java.awt.BorderLayout;

   import java.awt.event.ActionListener;
   import java.awt.event.ActionEvent;

   public class OnOffC
   extends JPanel
   implements Runnable, ActionListener
   {

      static final long serialVersionUID = 7046131319439923772L;
      String name = "";
      JButton    jbg    = new JButton ("Go");  // listener and constructor need to access this variable
      JTextField jt     = new JTextField ();   // constructor and run need to access this variable
      boolean    goFlag = false;               // run and listener need to access this variable
      long       delay  = 200L;                // thread polling delay
  
      public OnOffC (String n) {
         name = n;
         jbg.setText (jbg.getText() + " " + name);
         setLayout (new GridLayout (1, 0));
         add (jbg);
         add (jt);
        
         jt.setHorizontalAlignment (JTextField.RIGHT);
        
         jbg.addActionListener (this);
              
         new Thread (this).start();
     
} // end String constructor
  
      public void actionPerformed (ActionEvent e) {
         if (goFlag) {
            goFlag = false;
            jbg.setText ("Go " + name);
         }
         else {
            goFlag = true;
            jbg.setText ("Stop " + name);
            synchronized (this) {
               notify ();}

         }
     
} // end method action Performed
     
      public void run () {
         int count = 0;
         while (true) {
            try {
               jt.setText (String.format ("%d", count++));
               Thread.sleep (delay);
               synchronized (this) {
                  while (!goFlag) {wait (); System.out.println ("Checking: " + name);}}

            }
               catch (InterruptedException e) {
               }
         } // end run forever
     
} // end method run
     
      static JFrame createFrame (String t) {
         JFrame jf = new JFrame (t);
         jf.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
         jf.setLayout (new GridLayout (0, 1));
         jf.setLocationRelativeTo (null);
         jf.setSize (250, 180);
         jf.setVisible (true);
     
         JButton jbq = new JButton ("Quit");
         jf.add (jbq);
         jbq.addActionListener (
               new ActionListener () {
                  public void actionPerformed (ActionEvent e) {
                     System.exit(0);}
               });
     
         return jf;
     
} // end createFrame
  
      public static void main (String args []) {
         JFrame jf = createFrame ("An example");
         jf.add (new OnOffC ("A"));
         jf.add (new OnOffC ("B"));
         jf.add (new OnOffC ("C"));
         jf.add (new OnOffC ("D"));
         jf.add (new OnOffC ("E"));
         jf.validate (); // keep frame size, layout the panels and buttons inside
     
} // end method main 
  
  
} // end class OnOffC

RunEx.java

// File: RunEx.java
// Date: Aug 16, 2010
// Author: Nick Duchon

public class RunEx implements Runnable {
  public void run () {
    System.out.println ("Inside run");
 
} // end interface method run
 
  public static void main (String args []) {
    RunEx r = new RunEx ();
    Thread t = new Thread (r);
    t.start ();
 
} // end main
} // end class RunEx

RunExA.java

// File: RunExA.java
// Date: Aug 16, 2010
// Author: Nick Duchon

// Note: multiple threads with random delays, independent

import java.util.Random;

public class RunExA implements Runnable {
  static Random rn = new Random ();
  
  int id, count;
 
  public RunExA (int pid, int pcount) { id = pid; count = pcount;}
 
  public void run () {
    while (count > 0) {
      try {
        Thread.sleep (rn.nextInt (1000) + 10); // in ms
      } catch (InterruptedException e) {}
      System.out.println ("Inside run of " + id + ", count: " + count-- + ", Time: " + System.currentTimeMillis());
    } // end while
 
} // end interface method run
 
  public static void main (String args []) {
    RunExA ra = new RunExA (1, 10);
    RunExA rb = new RunExA (100, 10);
    Thread ta = new Thread (ra);
    Thread tb = new Thread (rb);
    ta.start ();
    tb.start ();
    System.out.println ("End main");
 
} // end main
} // end class RunEx

RunExB.java

// File: RunExB.java
// Date: Aug 17, 2010
// Author: Nick Duchon

// Note: multiple threads with array of delays, independent
// Usage: pattern of a's and b's separated by spaces, for example:
//  b b b a a b b b a a a a

import java.util.Scanner;

public class RunExB implements Runnable {
  static Scanner sn = new Scanner (System.in);
  final static int STARTVALUE = 5;
  static int mem = STARTVALUE; // SHARED resource
  
  String id;
  int count = 0, add, reg; // LOCAL resources
  int [] delays;
 
  public RunExB (String pid, int padd, int [] pDelays) {
    id = pid; add = padd; delays = pDelays;
 
} // end constuctor
 
  public void run () {
    for (int d: delays) {
      try {
        Thread.sleep (d*10); // in ms
        switch (count % 3) {
          case 0: reg  = mem; break;
          case 1: reg += add; break;
          case 2: mem  = reg; break;
        } // end switch
      } catch (InterruptedException e) {}
      System.out.printf ("Inside run of %s, count %d, Time: %d, mem: %2d, reg: %2d\n",
                         id, count++, System.currentTimeMillis(), mem, reg);
    } // end while
 
} // end interface method run
 
  public static void main (String args []) {
    while (menu ());
    System.out.println ("End main");
 
} // end main
 
  static boolean menu () {
    System.out.println ("Enter pattern, q to quit. Example: a a a b b a a");
    String str = sn.nextLine();
    if (str.toLowerCase().trim().startsWith ("q")) return false;
    int [] da, db;
    mem = STARTVALUE; // reset value of shared resource
   
    da = getPatternDelays (str.split("\\s"), "A");
    db = getPatternDelays (str.split("\\s"), "B");
   
    Runnable ra = new RunExB ("A  ", 8, da);
    Runnable rb = new RunExB ("  B", 3, db);
    Thread tha = new Thread (ra);
    Thread thb = new Thread (rb);
    tha.start ();
    thb.start ();
   
    displayInterleavedTimeline (da, db);
   
    // wait for both threads to finish before going on
    try {
      tha.join ();
      thb.join ();
    } catch (InterruptedException e) {}
   
    System.out.println ();
    return true;
 
} // end menu
 
  public static int [] getPatternDelays (String [] args, String pat) {
    int ic = 0, t = 0, tl = 0;

    for (String s: args)
      if (s.equalsIgnoreCase (pat))
        ic++;

    int [] r = new int [ic];
    ic = 0;
    for (String s: args) {
      t += 5;
      if (s.equalsIgnoreCase (pat)) {
        r[ic++] = t - tl;
        tl = t;
      } // pattern found, updat tl (last time this pattern found)
    } // end for token in string
    return r;
 
} // end method getPatternDelays
 
  public static void displayInterleavedTimeline (int [] da, int [] db) {
      // display timeline, interleaving a and b
    int ia = 0, ib = 0, nia, nib;
    int ta = 0, tb = 0, t = 0;
    while (true) {
      if (ia >= da.length && ib >= db.length) break; // end of both arrays
      nia = (ia < da.length) ? da[ia]+ta : Integer.MAX_VALUE;
      nib = (ib < db.length) ? db[ib]+tb : Integer.MAX_VALUE;
      if (nia < nib) {
        t = ta = nia;
        ia ++;
        System.out.printf ("a[%d]  : %d\n", ia, t);
      } else {
        t = tb = nib;
        ib ++;
        System.out.printf ("  b[%d]: %d\n", ib, t);
      } // print next event
     
    } // end while either array has more elements
 
} // end static method displayInterleavedTimeline
 
} // end class RunEx

Thread Contention Experiments:

public class TaskThreadDemo2 {
  public static void main (String args []) {
    String [] sa = {"a", "X", "+", "."};
    Thread ts;
    for (String s: sa) {
      Runnable ps = new PrintChar2 (10_000_000);
      ts = new Thread (ps, s);
      ts.start (); // start () vs run() !
    } // end for each character
  } // end main
} // end class TaskThreadDemo

class PrintChar2 implements Runnable {
  static int sum; // try without static !
  int times;
 
  public PrintChar2 (int n) {
    times = n;
  } // end constructor
 
  // try synchronized : method, this, class
  public void run () {
    for (int i = 0; i < times; i++) {
      sum = sum + 1;
//    synchronized (PrintChar2.class) { sum = sum + 1;}
    } // end for loop
    System.out.printf ("%s: %,d\n",
      Thread.currentThread().getName(),
      sum);
  } // end method run
} // end class PrintChar


Executor Pools

// File: WorkerThread.java
// Date: Oct 3, 2015
// Author: Nicholas Duchon
//   based on posting in CMSC 335b, Hassan Irfan
//   package com.journaldev.threadpool
// Purpose:
//   show one way to use executor pools

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class WorkerThread implements Runnable {
   static java.util.Random rn = new java.util.Random ();
   static int pools = 15, count = 50, delayms = 500;
   String command;

   public static void main(String[] args) {
      ExecutorService executor = Executors.newFixedThreadPool(pools);
      for (int j = 0; j < count; j++)
        executor.execute(new WorkerThread("" + j));
      executor.shutdown();
      // CPU usage:
      //   try/catch around  0.2%
      //   while     around 25.0%
      try   {executor.awaitTermination (10, TimeUnit.MINUTES);}
      catch (InterruptedException e) {}
//       while (!executor.isTerminated()); // REALLY BAD idea - spinning on this.
      System.out.println(">> Finished all threads");
   } // end method main

   public WorkerThread(String d){
      command = d;
   } // end String constructor

   public void run() {
      String threadID = Thread.currentThread().getName();
      System.out.printf ("Starting: %-16s, %3s +\n", threadID, command);
        try   {Thread.sleep(rn.nextInt(delayms));}
        catch (InterruptedException e) {}
      System.out.printf ("..Ending: %-16s, %3s .\n", threadID, command);
  } // end interface method run

} // end class WorkerThread


Interleaving Output:

// File: TaskThreadDemo.java
// Date: Nov 1, 2017
// Author: Nicholas Duchon
// Purpose: show interleaving threads

public class TaskThreadDemo {

  public static void main (String args []) {
    String [] sa = {"a", "X", "+", "."};
    for (String s: sa) {
      Runnable ps = new PrintChar (s, 200);
      Thread ts = new Thread (ps, s);
      ts.start ();
    } // end for each character
  } // end main
} // end class TaskThreadDemo

class PrintChar implements Runnable {
  String ch;
  int times;

  public PrintChar (String c, int n) {
    ch = c;
    times = n;
  } // end constructor

  public void run () {
    for (int i = 0; i < times; i++) {
      System.out.print (ch);
    } // end for loop
  } // end method run
} // end class PrintChar


End.
Last updated: Oct 3, 2015