title: Starting and Stopping Threads with Buttons
body: <p>I have what I thought was a simple problem, which I have yet to find a good solution to:  I would like to be able to pause and unpause the activity taking place in a thread, by hitting a button on a Swing interface panel.</p>
  
  <p>Specifically, I would like to use one thread to take in audio frames in real time; a second thread to perform magic processing on those frames; and a third thread to serialize the results and send over a socket somewhere else.  The kicker is that depending on the brand of magic we employ, the processing in the second thread might take longer per frame to perform than the actual data collection, and the data might pile up after a while.  </p>
  
  <p>As a <strong>very crude prototype workaround</strong> we thought we'd add a GUI with a button to turn the audio collection process on and off and a status bar (to be implemented later) so that a user could sort of keep an eye on how full the buffer (a linked blocking queue) happened to be.</p>
  
  <p>This is harder than I anticipated.  I've stripped the problem down to a toy version:  A linked blocking queue that can store 50 Integers, a GUI, two threads (adding to and removing from the queue at different rates) and a Token object wrapped around a boolean.  It looks like this, and it sorta works:</p>
  
  <p><strong>Test.java</strong></p>
  
  <pre><code>public class Test {
    public static void main(String[] args) throws IOException {
  
      Token t1 = new Token();
      Token t2 = new Token();
      LinkedBlockingQueue&lt;Integer&gt; lbq = new LinkedBlockingQueue&lt;Integer&gt;(50);
  
      startFill sf = new startFill(t1, lbq);
      startEmpty se = new startEmpty(t2, lbq);
  
      TestUI testUI = new TestUI(t1, t2, lbq);
      testUI.setVisible(true);
  
      sf.start();
      se.start();
    }
  }
  </code></pre>
  
  <p><strong>TestUI.java</strong></p>
  
  <pre><code>public class TestUI extends JFrame implements ActionListener {
    private JToggleButton fillStatus, emptyStatus;
    public boolean filling, emptying;
    public Token t1, t2;
    public LinkedBlockingQueue&lt;Integer&gt; lbq;
  
    public TestUI(Token t1, Token t2, LinkedBlockingQueue&lt;Integer&gt; lbq) {
      this.t1 = t1;
      this.t2 = t2;
      this.lbq = lbq;
      initUI();
    }
  
    public synchronized void initUI() {
      JPanel panel = new JPanel();
      panel.setLayout(null);
  
      filling = false;
      fillStatus = new JToggleButton("Not Filling");
      fillStatus.setBounds(20, 20, 150, 25);
      fillStatus.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          if (filling == false) {
            fillStatus.setText("Filling");
          } else {
            fillStatus.setText("Not Filling");
          }
          filling = !filling;
          t1.flip();
          System.out.println("fill button press");
        }
      });
  
  // Similar code for actionListener on Empty button, omitted
  
      panel.add(fillStatus);
      panel.add(emptyStatus);
      add(panel);
      setTitle("Test interface");
      setSize(420, 300);
      setLocationByPlatform(true);
      setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
  
    public void actionPerformed(ActionEvent e) {
    }
  }
  </code></pre>
  
  <p><strong>startFill.java</strong></p>
  
  <pre><code>public class startFill extends Thread {
    public Token token;
    public LinkedBlockingQueue&lt;Integer&gt; lbq;
  
    public startFill(Token token, LinkedBlockingQueue&lt;Integer&gt; lbq) {
      this.token = token;
      this.lbq = lbq;
    }
  
    public void run() {
      int count = 0;
      while (true) {
        while (!token.running()) {
          try {
            sleep(200);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
  
        while (token.running()) {
          try {
            lbq.put(count);
            System.out.println("queue size = " + lbq.size());
            count++;
            sleep(100);
          } catch (InterruptedException e1) {
            e1.printStackTrace();
          }
        }
      }
    }
  }
  </code></pre>
  
  <p>There is also a startEmpty.java that works about the same way, and a Token.java that's a wrapper for a boolean state variable, omitted for merciful brevity.  </p>
  
  <p>So that works, but at the expense of polling in the <code>while (!token.running())</code> loop.
  I tried using Locks and Conditions, but failed, always getting IllegalMonitorStateExceptions.</p>
  
  <p>And I looked at this <a href="https://stackoverflow.com/q/3179356/1092746">similar question</a> and managed to get that working, but at the expense of using the yield() method which apparently differs significantly between Java 5 and Java 6, and seems to be highly discouraged.</p>
  
  <p>So my question:  <strong>Is there some correct, or significantly better way to do what I am trying to do?</strong>  It seems like there should be a way to make this happen without the polling and with reliable methods.  </p>
  
  <p><strong>Update:</strong> I'm not sure I can get around the issue of controlling the audio capture loop <em>in some way</em> for the application.  Whether it is a human pressing a button, or internal logic making decisions based on some other factors, we really need to be able to shut the darn thing down and bring it back to life on command.  </p>