java - 如何正确使用通知和等待
问题描述
如何正确使用通知和等待。我只有两个线程来测试我的逻辑。是不是如下我创建了一个线程,它将执行get类型的命令并使用cmdfile_1 file_2
创建。我的第一个任务没有,因此它将在条件谓词上置于等待状态,该条件谓词检查两个文件是否都存在于文件上的 .exists() 方法。第二个线程将创建并通知第一个线程,然后另一个线程将唤醒并执行他的工作。问题是,在等待的线程唤醒后,它没有他的工作,而是另一个线程的工作。例如,如果必须执行并且它处于等待状态。并且必须执行所以它创建并通知file3
type
file_2
file_2
Thread-1
file1 file2 > file3
Thread-2
file3 file4 > file2
file2
Thread-1
. 在 Thread-1 醒来后,它拥有file3 fil4 > file2
而不是他的文件。我将所有内容都转储到控制台,当两个线程从命令文件中获取任务时,它们会获取正确的任务,但它们没有相同的任务,但在Thread-1
醒来后它就有了Thread-2
任务。有人可以帮助我了解如何在这种情况下以及在任何其他情况下使用等待和通知。我在实践中阅读了 Java 并发,但他们只在其中放置和获取方法,等待和通知,而且谷歌中的示例很天真,它们按预期工作。提前致谢。
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class MyTaskManager {
private static AtomicInteger id = new AtomicInteger();
private static String[] in;
private static String cmd;
private static Task task;
private static Process process;
private static MyTaskManager taskManager;
public static void main(String[] args) {
taskManager = new MyTaskManager();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
// Assign work
synchronized (taskManager) {
String line = Files.readAllLines(Paths.get("commands.txt"))
.get(id.get());
id.getAndIncrement();
in = line.split(" ");
cmd = in[0] + " " + in[1] + " " + in[2] + " " + in[3] + " " + in[4];
task = new Task(cmd);
System.out.println(cmd);
}
// After the thread is woked up it checks the condition again
// but this time it is taken the other thread object
synchronized (taskManager) {
while (!task.checkCondition(task)) {
System.out.println("Waiting thread " + Thread.currentThread().getName());
System.out.println("Write file in wait " + task.getOutput_file());
System.out.println("---------------------------------");
taskManager.wait();
System.out.println(Thread.currentThread().getName() + " after sleep");
}
}
process = Runtime.getRuntime()
.exec("cmd /c start cmd.exe /k \"" + task.getCmd() + "\"");
process.waitFor();
synchronized (taskManager) {
taskManager.notifyAll();
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
// Assign work
synchronized (taskManager) {
String line = Files.readAllLines(Paths.get("commands.txt"))
.get(id.get());
id.getAndIncrement();
in = line.split(" ");
cmd = in[0] + " " + in[1] + " " + in[2] + " " + in[3] + " " + in[4];
task = new Task(cmd);
System.out.println(cmd);
}
process = Runtime.getRuntime()
.exec("cmd /c start cmd.exe /k \"" + task.getCmd() + "\"");
process.waitFor();
synchronized (taskManager) {
taskManager.notifyAll();
System.out.println("Notifying " + Thread.currentThread().getName());
}
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
});
BlockingQueue<Runnable> worksQueue = new
ArrayBlockingQueue<>(10);
RejectedExecutionHandler rejectionHandler = new
RejectedExecutionHandlerImpl();
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 20,
TimeUnit.SECONDS, worksQueue, rejectionHandler);
executor.prestartAllCoreThreads();
List<Runnable> taskGroup = new ArrayList<>();
taskGroup.add(t);
taskGroup.add(t1);
worksQueue.add(new MultiRunnable(taskGroup));
executor.shutdown();
}
}
boolean checkCondition(Task task) {
String[] in = task.cmd.split(" ");
File dep1 = new File(in[1]);
File dep2 = new File(in[2]);
return dep1.exists() && dep2.exists();
}
解决方案
在您的情况下,相互等待通知调用的问题是一个线程可以notify
在另一个线程调用之前完成其工作并调用wait
。通知不会“记住”,因此如果在实际调用之前调用了通知wait
,那么等待线程将永远等待(嗯,直到另一个通知)。
如果我没记错的话,你希望 T1 必须做一些工作,等待来自 T2 的一些通知,然后做一些其他的 + 退出。CountDownLatch
如果这是正确的,那么您使用或使用起来会简单得多Semaphore
两者都可以取消上述赛车条件的影响。当其他线程等待它这样做时,或者在这将导致“等待线程”永远不必等待“门已经打开”时,倒计时锁可以“倒计时”。
推荐阅读
- javascript - 移除 HTML、HEAD 和 BODY 标签以获取 SVG
- flutter - suffixIcon 阻止 TextFormField 的输入
- javascript - javascript 功能中的生成器函数
- java - 在 JPA 中访问 Root 对象的嵌套对象时出现 NullPointerException
- flutter - Flutter中如何提高Yolov4-tiny.tflite的准确率
- javascript - Javascript中有没有办法逐渐更新元素而不是同时更新
- javascript - 对对象的代理数组进行排序,localeCompare 不是函数
- reactjs - React 路由器和 Apache + Nginx 提供 Unexpected Token <
- python - 硒类跨度不断变化的python
- python - 如何在 JSON 中将变量作为值传递