Java 确保所有等待线程都已完成
我正在构建一个系统,其中调用线程的进度取决于两个变量的状态。一个变量由独立于客户端线程的外部源偶尔更新,多个客户端线程在两个变量都存在的情况下阻塞。系统是这样的Java 确保所有等待线程都已完成,java,multithreading,concurrency,Java,Multithreading,Concurrency,我正在构建一个系统,其中调用线程的进度取决于两个变量的状态。一个变量由独立于客户端线程的外部源偶尔更新,多个客户端线程在两个变量都存在的情况下阻塞。系统是这样的 TypeB waitForB() { // Can be called by many threads. synchronized (B) { while (A <= B) { B.wait(); } A = B; return B; { } void update
TypeB waitForB() { // Can be called by many threads.
synchronized (B) {
while (A <= B) { B.wait(); }
A = B;
return B;
{
}
void updateB(TypeB newB) { // Called by one thread.
synchronized (B) {
B.update(newB);
B.notifyAll(); // All blocked threads must receive new B.
}
}
我需要所有被阻止的线程在更新后接收新的B值。但问题是,一旦一个线程完成并更新了a,等待条件再次变为真,因此其他一些线程被阻塞,并且没有收到新的值B。是否有办法确保只有在B上阻塞的最后一个线程更新了a,还是获得这种行为的另一种方法?我的建议是使用基于事件的方法,线程想知道新的B值,只需注册更改!而单线程只是调用触发器。 像这样的。 首先声明事件标志
interface EventListener{
void onUpdate(TypeB oldOne,TypeB newOne);
}
然后将实现作为侦听器
class ManyThread implements EventListener,Runnable{
...
private TypeA a;
synchronized void onUpdate(TypeB oldOne,TypeB newOne){
if(!oldOne.equals(newOne)){a=newOne;this.notify();}
}
public ManyThread(){SingleThread.registerListener(this);}
public synchronized void run(){
this.wait();//waiting for an event!
//some business
}
...
}
然后提供事件发布者
final class EventMgr{//would be as a singleton guy too
private EventMgr(){}
static private java.util.List<EventListener> li=new java.util.ArrayList<EventListener>();
static synchronized public void registerListener(EventListener e){li.add(e);}
static synchronized void triggerListeners(TypeB oldOne,TypeB newOne){
for(EventListener e:li){e.onUpdate(oldOne,newOne)}
}
}
我有以下想法:为了让线程的计数器等待B的好值,首先唤醒的线程将缓存该好值,并让其他读卡器在该时刻读取它。在前一轮的线程都完成之前,我们不让新的读卡器进入等待循环 下面是代码的概要:
final AtomicInteger A = new AtomicInteger(-1), B = new AtomicInteger(-1);
int cachedB = -1;
int readersCount;
int waitForB() throws InterruptedException { // Can be called by many threads.
synchronized (B) {
while (cachedB != -1) B.wait();
readersCount ++;
while (A.get() <= B.get()) { B.wait(); }
if (cachedB == -1) {
cachedB = B.get();
A.set(B.get());
readersCount--;
if (readersCount == 0) { cachedB = -1; B.notifyAll(); }
return B.get();
} else {
int ret = cachedB;
readersCount--;
if (readersCount == 0) { cachedB = -1; B.notifyAll(); }
return ret;
}
}
}
void updateB(int newB) { // Called by one thread.
synchronized (B) {
B.set(newB);
B.notifyAll(); // All blocked threads must receive new B.
}
}
我不确定这是否是100%线程安全的,但我还没有发现任何问题。这个想法是这样的:
CyclicBarrier barrier;
AtomicInteger count = 0;
TypeB waitForB() { // Can be called by many threads.
synchronized (B) {
count++;
while (A <= B) { B.wait(); }
count--;
{
if (barrier != null) { barrier.await(); }
return B;
}
class UpdateA implements Runnable {
void run() {
A = B;
}
}
void updateB(TypeB newB) { // Called by one thread.
synchronized (B) {
B.update(newB);
barrier = new CyclicBarrier(count, new UpdateA);
B.notifyAll(); // All blocked threads must receive new B.
}
}
检查volatile关键字在threadingHe's中的作用他似乎没有在A@DanielGabriel上同步。@DanielGabriel A=B没有改变B。你能解释一下你的具体用例吗?在这个玩具示例中,您描述的问题是通过替换一个锁来解决的。通常建议锁定在其所有者之外看不到的对象上,以免其他代码窃取您的锁并破坏整个同步机制。如果A或B将被返回,请注意。感谢您的回答,但不幸的是,我无法修改调用客户端线程。我想试着用一辆自行车或类似的东西。这是个棘手的问题。嗨,维克多,我喜欢你的解决方案!我想我找到了另一个使用自行车的解决方案。我会将您的解决方案标记为正确,然后发布我的解决方案。谢谢
CyclicBarrier barrier;
AtomicInteger count = 0;
TypeB waitForB() { // Can be called by many threads.
synchronized (B) {
count++;
while (A <= B) { B.wait(); }
count--;
{
if (barrier != null) { barrier.await(); }
return B;
}
class UpdateA implements Runnable {
void run() {
A = B;
}
}
void updateB(TypeB newB) { // Called by one thread.
synchronized (B) {
B.update(newB);
barrier = new CyclicBarrier(count, new UpdateA);
B.notifyAll(); // All blocked threads must receive new B.
}
}