我正在构建一个系统,其中调用线程的进度取决于两个变量的状态。一个变量偶尔由外部源(与客户端线程分开)更新,多个客户端线程在两个变量的条件下阻塞。系统是这样的
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或其他获取此行为的方式上被阻止?
答案 0 :(得分:0)
我的建议是使用基于事件的方法,线程想知道新的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)}
}
}
和EventMgr
家伙的简单触发器监听器
class SingleThread{
TypeB oldOne,B;
void updateB(TypeB newB) { // Called by one thread.
synchronized (B) {
oldOne=B.clone();
B.update(newB);
//B.notifyAll();
EventMgr.triggerListeners(oldOne,B);
}
}
}
答案 1 :(得分:0)
我有以下想法:保持线程的计数器等待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.
}
}
答案 2 :(得分:0)
我不确定这是否是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.
}
}