如何等待并通知两个独立的线程?

时间:2016-08-28 19:04:20

标签: java multithreading

我使用ExecutorService创建了两个独立的线程。现在我只想要一个线程将数据写入文件,另一个线程将在从线程发送通知后读取它,该线程将数据写入文件,但输出没有显示任何内容,因此如何实现我的目标。 / p>

My code is:
package threadingexamples;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadingExamples {

public static void main(String[] args) throws InterruptedException {
    ExecutorService es = Executors.newFixedThreadPool(2);
    es.submit(new ForLoo1());
    es.submit(new ForLoop2());

    es.shutdown();
    es.awaitTermination(1, TimeUnit.DAYS);

    System.exit(0);
}

}

class ForLoo1 implements Callable<Object> {

@Override
public Object call() throws Exception {

    System.out.println("I am writing content into file....");

    String s = "This is the content to write into a file";

    File file = new File("/home/f.txt");

    if (!file.exists()) {
        file.createNewFile();
    }

    FileWriter fw = new FileWriter(file);
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(s);
    bw.close();
    System.out.println("Now you can read content from files...");
    notify();
    return null;
}

}

class ForLoop2 implements Callable<Object> {

    @Override
    public Object call() throws Exception {

        wait();
        System.out.println("Okay i am now going to read content of   files...");

        BufferedReader br = new BufferedReader(new FileReader("f.txt"));
        String str;
        while ((str = br.readLine()) != null) {
            str = str + "";
        }
        System.out.println("I am done with reading.....");
        System.out.println(str);
        return null;
    }

}

3 个答案:

答案 0 :(得分:2)

您可以使用以下代码达到预期效果。通过调用document.fileinfo.action = "<%=uploadJSP%>"中的await,线程只会在ForLoop2中调用countDown后唤醒。 CountDownLatch是一种多功能的同步工具。

ForLoop1

答案 1 :(得分:0)

您可以使用Future来完成此操作。提交第一个任务会返回一个Future,第二个任务可以用来在任务完成后检索第一个任务的返回值;接收未来的Callable任务将阻塞,直到get方法收到结果。我更改了第一个callable以返回非null值:

package threadingexamples;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Future;

public class ThreadingExamples {

    public static void main(String[] args) throws InterruptedException {

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Object> future = es.submit(new ForLoo1());
        es.submit(new ForLoop2(future));

        es.shutdown();
        es.awaitTermination(1, TimeUnit.DAYS);
    }

}

class ForLoo1 implements Callable<Object> {

    @Override
    public Object call() throws Exception {

        System.out.println("I am writing content into file....");

        String s = "This is the content to write into a file";

        File file = new File("/home/f.txt");

        if (!file.exists()) {
            file.createNewFile();
        }

        FileWriter fw = new FileWriter(file);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write(s);
        bw.close();
        System.out.println("Now you can read content from files...");
        return "ok";
    }
}

class ForLoop2 implements Callable<Object> {

    private Future<Object> future;

    public ForLoop2(Future<Object> future) {
        this.future = future;
    }

    @Override
    public Object call() throws Exception {
        System.out.println("in ForLoop2, ");
        Object ok = future.get();

        System.out.println("Okay i am now going to read content of   files...");

        BufferedReader br = new BufferedReader(new FileReader("f.txt"));
        String str;
        while ((str = br.readLine()) != null) {
            str = str + "";
        }
        System.out.println("I am done with reading.....");
        System.out.println(str);
        return null;
    }
}

或者您可以使用BlockingQueue,将其传递到每个Callable的构造函数中。一个Callable将一个条目放入队列,另一个条目从中读取。这更适合于您希望在线程之间传递多条消息的情况。但是,原则相同:将等待/通知代码放在数据结构中,而不是放在任务中。

答案 2 :(得分:-1)

编辑:这是不该做的一个例子。请使用CountDownLatch方法;在大多数程序中,您不需要使用notifywait。另外,请阅读以下评论,了解为什么这是一个坏主意。即使添加了synchronized块(需要调用notifywait),仍然存在可能导致ForLoop2死锁的竞争条件。

你几乎得到了它!当您在上面的代码中致电wait()notify()时,他们会在不同的对象中被调用。试试这个:

Object monitorObject = new Object();
es.submit(new ForLoo1(monitorObject));
es.submit(new ForLoop2(monitorObject));

...


class ForLoop1 implements Callable<Object> {
    private final Object monitorObject;

    public ForLoop1(Object monitorObject) {
         this.monitorObject = monitorObject;
    }

    @Override
    public Object call() throws Exception {

        ...
        synchronized(monitorObject) {
            monitorObject.notify();
        }
    }
}

class ForLoop2 implements Callable<Object> {
    private final Object monitorObject;

    public ForLoop2(Object monitorObject) {
         this.monitorObject = monitorObject;
    }

    @Override
    public Object call() throws Exception {

        synchronized(monitorObject) {
            monitorObject.wait();
        }
        ...
    }
}