简体   繁体   English

如何正确使用notify和wait

[英]How to properly use notify and wait

How to use notify and wait properly.如何正确使用通知和等待。 I have just two threads to test my logic.我只有两个线程来测试我的逻辑。 Is it as follows i create one thread which will execute a command of the type get file_1 file_2 and create file3 with the type cmd.是不是如下我创建一个线程,它将执行类型为 get file_1 file_2的命令并创建type cmd 的file3 My first task don't have file_2 so it will be put in wait state on a condition predicate that checks if the both files are present with .exists() method on the file.我的第一个任务没有file_2因此它将在条件谓词上处于等待状态,该条件谓词检查两个文件是否都存在文件上的 .exists() 方法。 The second thread will create file_2 and it will notify the first thread then the other thread will wake up and execute his job.第二个线程将创建file_2并通知第一个线程然后另一个线程将唤醒并执行他的工作。 The problem is that after the thread that is waiting wakes up it doesn't have his job but the other's thread job.问题是在等待的线程唤醒后,它没有他的工作,而是另一个线程的工作。 For example if Thread-1 have to execute file1 file2 > file3 and it is in a wait state.例如,如果Thread-1必须执行file1 file2 > file3并且它处于等待状态。 And Thread-2 have to execute file3 file4 > file2 so it creates the file2 and notify Thread-1 .并且Thread-2必须执行file3 file4 > file2所以它创建file2并通知Thread-1 After Thread-1 woke up it have file3 fil4 > file2 and not his files.线程 1 醒来后,它有file3 fil4 > file2而不是他的文件。 I am dumping everything to the console and when the two threads are taking the tasks from the commands file they take the proper one's they don't have the same task but after Thread-1 woke up it have the Thread-2 task.我正在将所有内容转储到控制台,当两个线程从命令文件中获取任务时,它们会获取正确的任务,但它们没有相同的任务,但是在Thread-1唤醒后,它具有Thread-2任务。 Can someone help me to understand how to use wait and notify for this case and in any other of course.有人可以帮助我了解如何在这种情况下以及在任何其他情况下使用等待和通知。 I have read Java Concurrency in practice but they have only put and take methods there with wait and notify also the examples in google are naive and they work as expected.我已经在实践中阅读了 Java Concurrency,但他们只在那里放置和使用方法并等待并通知 google 中的示例是幼稚的,它们按预期工作。 Thanks in advance.提前致谢。

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();
    }

The problem with mutual wait-notify calls in your case is the fact that that one thread can finish its job and invoke notify before another thread invokes wait .在您的情况下,相互 wait-notify 调用的问题在于,一个线程可以完成其工作并在另一个线程调用wait之前调用notify Notification is not "remembered" so if notify is called before actual wait is, then waiting thread will wait forever (well, until another notify).通知不会“记住”,因此如果在实际wait之前调用通知,则等待线程将永远等待(好吧,直到另一个通知)。

If I am not mistaken, you want T1 has to do some job, wait for some notification from T2 and then do some other + exit.如果我没记错的话,你想让 T1 做一些工作,等待 T2 的一些通知,然后做一些其他的 + 退出。 If this is correct, it will be much simpler for you to use CountDownLatch or Semaphore如果这是正确的,那么使用CountDownLatchSemaphore会简单得多

Both can cancel effect of racing conditions mentioned above.两者都可以取消上述赛车条件的影响。 Countdown latch can be "counted down" when other threads are waiting for it to do so, or prior that which will result in "waiting thread" to never have to wait as "the door is already opened".当其他线程正在等待它这样做时,倒计时闩锁可以“倒计时”,或者在这之前会导致“等待线程”永远不必等待,因为“门已经打开”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM