我有一个用于执行货币兑换监控活动的类,它有能力暂停和恢复。关于班级设计,我有以下问题。
has_started
成为易变的?suspend
视为易变?我看过Exampledepot的示例,标记没有标记为volatile。InterruptedException
期间抓住wait
时,我应该return
,还是应该忽略该异常?此外,我收到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);
}
答案 0 :(得分:4)
(1,2)由于两个变量只在同步块中访问,因此它们不必是易失性的。
(3)通常最好用InterruptedException做一些事情。但是,如果您控制进程中的所有代码并且永远不会中断线程,则可以忽略它。
如果未仔细编写代码,嵌套的同步块可能会导致死锁。您必须始终(所有代码路径)以相同的顺序获取锁。
我同意juskt关于“Java Concurrency in Practice”的观点。这是一本非常好的书。
答案 1 :(得分:1)
has_started
,您通常会将其标记为volatile
。由于只在同步块中访问它,因此无需执行此操作suspend
,因此您通常会将其标记为volatile
。由于只在同步块中访问它,因此无需执行此操作InterruptedException
做一些事情是一种好习惯。 InterruptedException
表示您的等待已被其他线程中断 - 可能是来自浏览器插件(对于applet)或应用程序服务器(在JavaEE中)的关闭线程。当您捕获中断的异常时,建议您执行的操作是调用Thread.currentThread().interrupt();
来处理它。这就是你的遗嘱执行人所期望的。优秀的书籍Java Concurrency in Practice正是您需要深入了解并发性的细节。