Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 确保所有等待线程都已完成_Java_Multithreading_Concurrency - Fatal编程技术网

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.
    }
}