gpt4 book ai didi

java - 在递归 block 内使用 CountDownLatch 和 Object.wait 挂起

转载 作者:行者123 更新时间:2023-12-01 11:47:09 25 4
gpt4 key购买 nike

问题:在尝试分阶段检索递归 block 内的值时,执行会挂起。

说明: CountDownLatchObject.wait 用于实现递归 block 内分阶段访问值。但是,程序挂起并显示以下输出:

2 < 16
3 < 16
4 < 16
5 < 16
Current total: 5
Inside of wait
Inside of wait

程序:

import java.util.concurrent.*;
public class RecursiveTotalFinder {
private static CountDownLatch latch1;
private static CountDownLatch latch2;
private static CountDownLatch latch3;
public static void main(String... args) {
latch1 = new CountDownLatch(1);
latch2 = new CountDownLatch(1);
latch3 = new CountDownLatch(1);

//Create object
TotalFinder tf = new TotalFinder(latch1,latch2,latch3);

//Start the thread
tf.start();

//Wait for results from TotalFinder
try {
latch1.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}

//Print the result after 5th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();

//Wait for results again
try {
latch2.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}

//Print the result after 10th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();

//Wait for results again
try {
latch3.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}

//Print the result after 15th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
}
}


class TotalFinder extends Thread{
CountDownLatch tfLatch1;
CountDownLatch tfLatch2;
CountDownLatch tfLatch3;
private static int count = 1;
private static final class Lock { }
private final Object lock = new Lock();
private boolean gotSignalFromMaster = false;

public TotalFinder(CountDownLatch latch1, CountDownLatch latch2,
CountDownLatch latch3) {
tfLatch1 = latch1;
tfLatch2 = latch2;
tfLatch3 = latch3;
}

public void run() {
findTotal(16);
}

//Find total
synchronized void findTotal(int cnt) {
if(count%5==0) {
if(count==5)
tfLatch1.countDown();
if(count==10)
tfLatch2.countDown();
if(count==15)
tfLatch3.countDown();

//Sleep for sometime
try {
Thread.sleep(3000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Wait till current total is printed

synchronized(lock) {
while(gotSignalFromMaster==false) {
try {
System.out.println(" Inside of wait");
lock.wait();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
System.out.println("Came outside of wait");
}

}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}

//Return the count value
public int getCurrentTotal() {
return count;
}

//Release lock
public void releaseWaitLock() {
//Sleep for sometime
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}

synchronized(lock) {
gotSignalFromMaster=true;
lock.notifyAll();
}
}

//Reset wait lock
public void resetWaitLock() {
gotSignalFromMaster = false;
}
}

分析:在我的初步分析中,尽管从主程序调用了 notifyAll,但等待似乎是递归发生的。

帮助:为什么CountDownLatch没有生效后使用notfiyAll释放锁?需要有人帮助理解该程序到底发生了什么。

最佳答案

我从 JCIP 得到的关于 waitnotify 的主要信息是我可能会错误地使用它们,所以最好避免直接使用它们,除非绝对必要。因此,我认为您应该重新考虑这些方法的使用。

在这种情况下,我认为您可以使用 SynchronousQueue 来更优雅地完成它。也许这样的事情可能会起作用:

import java.util.concurrent.*;
public class RecursiveTotalFinder {
public static void main(String... args) throws InterruptedException {
SynchronousQueue<Integer> syncQueue = new SynchronousQueue<>();

//Create object
TotalFinder tf = new TotalFinder(syncQueue, 5);

//Start the thread
tf.start();

for (int i = 0; i < 3; ++i) {
System.out.println("Current total: " + syncQueue.take());
}
}
}

class TotalFinder extends Thread{
private final SynchronousQueue<Integer> syncQueue;
private final int syncEvery;
private int count;

public TotalFinder(SynchronousQueue<Integer> syncQueue,
int syncEvery) {
this.syncQueue = syncQueue;
this.syncEvery = syncEvery;
}

public void run() {
try {
findTotal(16);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}

//Find total
void findTotal(int cnt) throws InterruptedException {
if((count > 0) && (count%syncEvery==0)) {
syncQueue.put(count);
}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}
}
<小时/>

至于为什么你原来的方法不起作用,这是因为主线程将gotSignalFromMaster设置为true,然后立即返回false ,并且这发生在另一个线程能够检查其值之前。如果您在 resetWaitLock 中停留一段时间,它会继续超出当前挂起的点;但是,它会卡在最后而不是终止。

请注意,必须使用 Thread.sleep 来等待另一个线程更改某些状态是一个糟糕的方法 - 尤其是因为它会使您的程序非常慢。使用同步实用程序可以使程序更快、更容易推理。

关于java - 在递归 block 内使用 CountDownLatch 和 Object.wait 挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29066020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com