我有一堂课,用于执行货币兑换监控活动,并且具有暂停和恢复的功能。关于班级设计,我有以下问题。has_started
是否必须具有挥发性?suspend
是否必须具有挥发性?我从Exampledepot看过示例,该标志未标记为volatile。
当我在InterruptedException
期间遇到wait
时,我应该return
,还是忽略该异常?
另外,关于多个synchronized
块,我也收到NetBeans警告。这是有效的警告吗?
public synchronized void suspend() {
synchronized(currencyExchangeRunnable) {
suspend = true;
}
}
我的第一级同步用于防止多个线程执行挂起/恢复/启动/停止。我的第二个同步块是与
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);
}
最佳答案
(1,2)由于两个变量仅在同步块中访问,因此它们不必是volatile。
(3)通常最好用InterruptedException做些事情。但是,如果您控制进程中的所有代码,并且您从未中断线程,则可以忽略该线程。
如果代码编写不当,嵌套的同步块可能导致死锁。您必须始终(所有代码路径)以相同顺序获取锁。
我同意juskt的“ Java并发实践”。这是一本很好的书。
关于java - 有关挂起和恢复正在运行的线程的技术细节,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4727230/