簡體   English   中英

Java並發:resettable啟用/禁用等待條件

[英]Java concurrency: resettable enabled/disabled wait condition

我想讓一個線程睡眠,直到某個條件關閉。 基本上,我需要三個操作:

  • enable() :啟用睡眠模式(如果已啟用則不執行任何操作)
  • disable() :禁用睡眠模式(如果已禁用則不執行任何操作)
  • await() :等待睡眠模式被禁用(或者如果睡眠模式已被禁用則立即返回)或者線程被中斷(拋出InterruptedException

有了這個,線程A調用enable() 現在,線程B調用await()並進入休眠狀態,直到線程A (或另一個)調用disable() 可以重復該循環。

我知道這可以通過wait()notify()輕松完成,但我想知道JDK8是否內置了這樣的功能?

我能找到的最接近的是CountdownLatch(1) ,遺憾的是實現不可重置。

基本上,我只想調用enable() / disable()await() ,而所有並發概念都在實現中被抽象(盡管await()應該拋出InterruptedException ,這是不可避免的)。

您也可以使用Semaphor

import java.util.concurrent.Semaphore;

public class Switch {

    private Semaphore semaphore = new Semaphore(1);

    public void enable() {
        synchronized(this) {
            semaphore.drainPermits(); // 0
            semaphore.reducePermits(1); // -1 or 0
        }
    }

    public void disable() {
        semaphore.release(2); // 1 or 2
    }

    public void await() throws InterruptedException {
        semaphore.acquire();
        semaphore.release();
    }


}

Switch另一種可能實現:

public class Switch {
    private final AtomicBoolean state = new AtomicBoolean();

    public void enable() {
        state.set(true);
    }

    public void disable() {
        if (state.compareAndSet(true, false)) {
            synchronized (state) {
                state.notifyAll();
            }
        }
    }

    public void await() throws InterruptedException {
        if (state.get()) {
            synchronized (state) {
                while (state.get()) {
                    state.wait();
                }
            }
        }
    }
}

你可以使用Condition

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Switch {
    private final Lock lock = new ReentrantLock();
    private final Condition on = lock.newCondition();
    private final Condition off = lock.newCondition();
    private volatile boolean state = true; 

    public void enable() {
        try {
            lock.lock();
            state = true;
            on.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void disable() {
        try {
            lock.lock();
            state = false;
            off.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void await() {
        try {
            lock.lock();
            while(!state) {
                try {
                    off.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException("waiting interrupted.");
                }
            }
        } finally {
            lock.unlock();
        }
    }
}
enable(): enable sleeping mode (do nothing if already enabled)
disable(): disable sleeping mode (do nothing if already disabled)

do nothing if already enabled (disabled)是一個糟糕的設計,可能會導致細微的錯誤,難以重現和發現。 例如,禁用休眠模式,一個線程調用disable() ,另一個調用enable() 根據首先進行的呼叫,模式將永久保持啟用或禁用。 為了使執行更具確定性,必須計算啟用和禁用,並確定(禁用)最終狀態。

相反,你的線程應該交換不相互掩蓋的令牌 除了CountdownLatch (實際上是一個禁止的計數器),JDK還有CyclicBarrierPhaser ,它們是可重置的禁止計數器,而Semaphore是一個權限計數器。

UPDT這個實現可能有用(我沒有測試過):

Phaser p = new Phaser(1);

public void await() {
    p.arriveAndAwaitAdvance();
}

public void enable() {
    p.register();
}

public void disable() {
    p.arriveAndDeregister();
}

enable() N次連續調用需要相同數量的disable()來傳遞等待線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM