我正在尝试编写一些具有以下行为的代码:
我查看了使用Semaphore,CountDownLatch,甚至编写了我自己的AbstractQueuedSynchronizer,但没有一个符合上述要求。例如,CountDownLatch假设您知道要对X进行多少次调用,这是我们不知道的。
似乎我几乎想要一个CountUpDownLatch的混合物,也许是某种简单的AtomicBoolean,但这就是我目前正在使用的东西,我发现自己时不时会陷入僵局。然后,我正在使用一个sketchy looking implementation的CountUpDownLatch,它是HSQLDB的一部分,严重看起来不是线程安全的。
关于如何解决这个问题的任何想法?
答案 0 :(得分:3)
看起来像ReentrantReadWriteLock
的任务。像这样:
class A {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public void x() {
if (!lock.readLock().tryLock()) throw new RuntimeException();
try {
...
} finally {
lock.readLock().unlock();
}
}
public void y() {
lock.writeLock().lock();
try {
...
} finally {
lock.writeLock().unlock();
}
}
}
答案 1 :(得分:2)
Java 7正在推出一个新的并发构造类java.util.concurrent.Phaser。移相器是一个美化的圆柱形屏障,允许等待并发执行的特定阶段(或迭代)。您可以在JSR 166's Interest Site下载最新的二进制jar。
我的想法是你有一个不稳定的boolean yHasEnetered标志,它将默认值初始化为false。所以在你的X执行中你可以这样做:
if(yHasEnetered)
throw new IllegalStateException();
phaser.register();
//do work here
phasre.arrive();
移相器本身将保持所有注册方的运行计数,以便当Y线程进入时,它可以相应地设置标志,注册自己并等待提前。
yHasEntered=true;
int phase = phaser.register();
phaser.arriveAndAwaitAdvance(phase);
//do y work here
yHasEntered=false;
此时为Y线程。它将自己注册到相位器当前所处的阶段,到达并等待执行的所有其他线程到达它们各自的到达块。
答案 2 :(得分:0)
考虑使用ExecutorService的实现。使用submit()方法添加任务,然后告诉服务不要使用shutdown()方法接受更多任务 - 已经接受的任务将正常完成。
答案 3 :(得分:0)
好的,如何使用ActiveObject
?
class X {
private static final ExecutorService service = Executors.newCachedThreadPool();
public void x(){
//Using anonymous class for brevity. Normal Runnable is ok. May be static inner class.
service.submit(new Runnable(){
@Override
public void run(){
//do stuff
}
});
}
//Derived from Java6 ExecutorService API
public void shutDownAndAwait(){
service.shutdownNow();
try{
if (!service.awaitTermination(60, TimeUnit.SECONDS))
throw new TerminationException("Service did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
service.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}//shutdownAndAwait
}//X
class Y {
private final X x = //inject reference
public void y(){
x.shutdownAndAwait();
}
}
问题是现在执行x()是异步的,因此调用x()的原始线程在完成时不确定。当y()被调用时,它们不会被打断......