Technical detail regarding suspending and resuming a running thread
<p>I have a class which use to perform currency exchange monitoring activities, and it is having ability to suspend and resume. I have the following questions regarding my class design.</p>

<ol>
<li>Is it necessary to have <code>has_started</code> as volatile?</li>
<li>Is it necessary to have <code>suspend</code> as volatile? I had seen the example from <a href="http://www.exampledepot.com/egs/java.lang/PauseThread.html" rel="nofollow">Exampledepot</a>, the flag is not marked as volatile.</li>
<li>When I catch <code>InterruptedException</code> during <code>wait</code>, shall I <code>return</code>, or shall I just ignore the exception?</li>
</ol>

<p>Also, I am getting NetBeans warning on having multiple <code>synchronized</code> block. Is it a valid warning?</p>

<pre><code>public synchronized void suspend() {
    synchronized(currencyExchangeRunnable) {
        suspend = true;
    }
}
</code></pre>

<p>My first level synchronized are use to prevent multiple threads from executing suspend/resume/start/stop. And my second level of synchronized block, is to pair with <code>wait/notify</code></p>

<p>My initial testing on suspend/resume/start/stop is that, they work as expected. However, I am not sure is there any other catches behind?</p>

<hr>

<pre><code>import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author yccheok
 */
public class CurrencyExchangeMonitor {

    /**
     * Starts currency exchange monitoring activities. This method can be called
     * multiple times. start/stop/suspend/resume are being synchronized with
     * each others.
     */
    public synchronized void start() {
        if (has_started) {
            return;
        }
        executor.submit(currencyExchangeRunnable);
        has_started = true;
    }

    /**
     * Stop all currency exchange monitoring activities. Once it is stopped, it
     * cannot be started again. This method will only return once it is being
     * terminated completely. start/stop/suspend/resume are being synchronized
     * with each others.
     */
    public synchronized void stop() {
        executor.shutdownNow();
        try {
            executor.awaitTermination(100, TimeUnit.DAYS);
        } catch (InterruptedException ex) {
            log.error(null, ex);
        }
    }

    /**
     * Temporary suspend all ongoing monitoring activities. This method can be
     * called multiple times. start/stop/suspend/resume are being synchronized
     * with each others.
     */
    public synchronized void suspend() {
        synchronized(currencyExchangeRunnable) {
            suspend = true;
        }
    }

    /**
     * Resume all ongoing monitoring activities. This method can be called
     * multiple times. start/stop/suspend/resume are being synchronized with
     * each others.
     */
    public synchronized void resume() {
        synchronized(currencyExchangeRunnable) {
            suspend = false;
            currencyExchangeRunnable.notify();
        }
    }

    private class CurrencyExchangeRunnable implements Runnable {
        @Override
        public void run() {
            while (!executor.isShutdown()) {
                synchronized(this) {
                    while (suspend) {
                        try {
                            wait();
                        } catch (InterruptedException ex) {
                            log.error(null, ex);
                            // Usually triggered by executor.shutdownNow
                            return;
                        }
                    }
                }
            }
        }
    }

    private volatile boolean suspend = false;
    private volatile boolean has_started = false;
    private final CurrencyExchangeRunnable currencyExchangeRunnable = new CurrencyExchangeRunnable();
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private static final Log log = LogFactory.getLog(CurrencyExchangeMonitor.class);
}
</code></pre>
