有关挂起和恢复正在运行的线程的技术细节

时间:2011-01-18 17:45:26

标签: java

我有一个用于执行货币兑换监控活动的类,它有能力暂停和恢复。关于班级设计,我有以下问题。

  1. 是否有必要让has_started成为易变的?
  2. 是否有必要将suspend视为易变?我看过Exampledepot的示例,标记没有标记为volatile。
  3. 当我在InterruptedException期间抓住wait时,我应该return,还是应该忽略该异常?
  4. 此外,我收到NetBeans警告有多个synchronized阻止。这是一个有效的警告吗?

    public synchronized void suspend() {
        synchronized(currencyExchangeRunnable) {
            suspend = true;
        }
    }
    

    我的第一级同步用于防止多个线程执行suspend / resume / start / stop。我的第二级同步块,是与wait/notify

    配对

    我对暂停/恢复/开始/停止的初步测试是,它们按预期工作。但是,我不确定是否还有其他捕获物?


    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);
    }
    

2 个答案:

答案 0 :(得分:4)

(1,2)由于两个变量只在同步块中访问,因此它们不必是易失性的。

(3)通常最好用InterruptedException做一些事情。但是,如果您控制进程中的所有代码并且永远不会中断线程,则可以忽略它。

如果未仔细编写代码,嵌套的同步块可能会导致死锁。您必须始终(所有代码路径)以相同的顺序获取锁。

我同意juskt关于“Java Concurrency in Practice”的观点。这是一本非常好的书。

答案 1 :(得分:1)

  1. 由于多个帖子我更改了has_started,您通常会将其标记为volatile。由于只在同步块中访问它,因此无需执行此操作
  2. 由于多个主题可能会更改suspend,因此您通常会将其标记为volatile。由于只在同步块中访问它,因此无需执行此操作
  3. 总是对InterruptedException做一些事情是一种好习惯。 InterruptedException表示您的等待已被其他线程中断 - 可能是来自浏览器插件(对于applet)或应用程序服务器(在JavaEE中)的关闭线程。当您捕获中断的异常时,建议您执行的操作是调用Thread.currentThread().interrupt();来处理它。这就是你的遗嘱执行人所期望的。
  4. 优秀的书籍Java Concurrency in Practice正是您需要深入了解并发性的细节。