7

我一直在尝试自学并发性,但遇到了一个问题。我知道两个 Java 线程可以通过wait()和相互通信notify()。但是,这需要一个线程处于非活动状态,并且基本上“只是坐在那里”,直到另一个线程将其唤醒。

是否可以让两个线程同时运行并且仍然让它们监听来自另一个的通知?这将通过并发技术还是类似的东西来完成ActionListener

例如,我正在测试的项目基本上是一个网格,不同的实体在不同的单元格中游荡。当两个实体碰巧进入同一个单元格时,我希望一个实体通知另一个实体并基于此发生不同的事情(例如,问候:“你好!”)。但就目前而言,使用等待/通知范式,其中一个线程/实体必须简单地坐在一个单元中,等待另一个进入;他们都不能四处走动。

4

5 回答 5

5

有几种方法可以在线程之间进行通信。使用最常见的方法,您可以使用实例变量在线程之间共享信息,但您必须注意只从一个线程写入或同步对共享变量的任何更新。或者,您可以使用为线程间通信或在线程之间传递原始数据而设计的管道 I/O 流。一个线程将信息写入流,而另一个线程读取它。

这是一个示例方法,它将从慢速网络连接读取输出并使用线程将其转储到 System.out。

    public void threads() throws IOException {
    final PipedOutputStream outputForMainThread = new PipedOutputStream();
    new Thread(new Runnable() {
        @Override
        public void run() {
            while(moreDataOnNetwork()) {
                byte[] data = readDataFromNetwork();
                try {
                    outputForMainThread.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }).start();
    BufferedReader reader = new BufferedReader(new InputStreamReader(new PipedInputStream(outputForMainThread)));
    for(String eachLine = reader.readLine(); eachLine != null; eachLine = reader.readLine()) {
        System.out.println(eachLine);
    }
}

但是,听起来您几乎想要一种事件回调机制,其中一个线程(您的用户界面线程)在另一个线程检测到特定条件时得到通知。根据您的平台,其中大部分内容都已包含在内。例如,使用 Android,您可以有一个线程来确定网格实体已移动。它将向主用户界面线程发送更新以重新绘制屏幕。这样的更新可能类似于:

public void gridEntityDidUpdate(final Point fromLocation, final Point toLocation) {
    Activity activity = getMainActivity();
    activity.runOnUiThread(
            new Runnable() {
                @Override
                public void run() {
                    updateScreen(fromLocation, toLocation);
                    if(pointsAreCoincedent(fromLocation, toLocation)) {
                        System.out.println("Hello there!");
                    }
                }
            }
    );
}

private void updateScreen(Point fromLocation, Point toLocation) {
    //Update the main activity screen here
}

在这种情况下,您有一个后台线程来计算所有屏幕上元素的位置,并在元素位置发生变化时通知主线程。有一种提取方法可以确定 2 个点是否重合或相同。

于 2012-10-01T16:30:06.443 回答
1

您可以使用Erlang 语言在它们自己的地址空间中安全地进行通信,并作为线程的更好和安全的替代方案。ProcessesJava

于 2012-10-01T16:34:52.847 回答
1

我一直在尝试自学并发性,但遇到了一个问题。我知道两个 Java 线程可以通过 wait() 和 notify() 相互通信。

“经典”Java 线程教程在早期就教授等待/通知。回到 Java 1.1、1.2 的时间框架,这就是全部。

但是,如果您可以获得 Brian Goetz 的优秀“Java Concurrency in Practice”的副本,等待/通知直到第 IV 部分高级主题中的第 14 章“构建自定义同步器”才讨论。我在这里严重解释,但我得到的印象是“如果你已经阅读了之前的 300 页,并且到目前为止讨论的构建块都没有满足你的需求,那么你可以尝试使用等待/通知来构建你自己的”。

我的观点是,等待/通知虽然非常重要,但可能不是开始学习并发的最佳场所。这个问题(生产者/消费者,ExecutorService)中的一些答案/评论是指在 Java 5 中添加的更高级别的并发构建块。即使这些东西是后来添加的,它也是你应该首先学习的东西。

回到你的问题 - 这里有几个想法:

如果这是一个 GUI 应用程序并且您想让后台线程做一些工作,请查看SwingWorker。我已经成功使用 SwingWorker(第 9.3.3 节),其中后台线程从阻塞队列(第 5.3 节)读取消息并通过调用更高级别的“发布”方法通知 GUI 线程。没有“等待/通知”——至少在我的代码中没有。

如果应用程序不是基于 Swing 的,并且您希望不同的线程并行执行任务并偶尔相互发送消息,请考虑ZeroMQ “充当并发框架的套接字库”。使用 ZeroMQ,每个线程都在运行一个读取和处理消息的事件循环。线程可以通过向自己发送消息来安排自己的线程上的工作。它可以通过向该线程(套接字)发送消息来安排工作/通知不同的线程。

无论如何,祝你好运。

于 2012-10-01T18:14:33.017 回答
0

尝试使用ThreadManager类,它具有List<Thread>并且有点像信号量对象。您的线程应该能够从那里找到并引用其他线程。

于 2012-10-01T16:37:04.173 回答
0

是否可以让两个线程同时运行并且仍然让它们监听来自另一个的通知?

只要他们不等待,他们就可以同时做某事。如果他们似乎只是在等待对方,那么你最好用一个线程。(使用多线程并不总是更好)

这会通过并发技术还是像 ActionListener 之类的东西来实现?

更有可能是您如何分解问题的设计问题。当线程之间的交互最少时,线程工作得最好。如果它们高度依赖于彼此,则应考虑使用更少的线程。

但就目前而言,使用等待/通知范式,其中一个线程/实体必须简单地坐在一个单元中,等待另一个进入;

我根本不明白你为什么需要在这里等待/通知。当他们在同一个牢房中时,我会让他们四处走动并互相发送消息。

于 2012-10-01T16:37:35.417 回答