有没有办法在两个完全独立的线程之间进行通信?

Is there a way to communicate between two completely independent threads?

我正在尝试在 Java 中不共享任何对象的两个线程之间进行通信(我正在构建一个 Java 代理)。我需要的是如下内容:

Thread agentattachThread = ...;
otherThread.send("Hello");

这将像代理附加线程中的中断一样处理,如下所示:

public void msgHandler(String msg) {
    ...
}

Thread.onMessageReceived(msgHandler);

EDIT - 考虑到我原来的 post 的答案,我的问题变成了:默认情况下,JVM 是否提供所有线程都可以引用的同步对象到?

我找到了一些选择。

  1. NIO 管道。
  2. 套接字。
  3. 全局同步对象。
  4. 信号。

我认为信号和回调机制是你所需要的。你必须自己实现它或使用第三方工具。

线程之间“通信”的唯一方法无需共享某些对象是通过Thread.interrupt() Obviously, the only signal you can send by this means is a true flag, and the receiver will only notice it when it uses certain methods, like Thread.interrupted(),或引发InterruptedException的方法。

由于这是如此有限,标准做法是在提供应用程序所需接口的线程之间共享线程安全对象。例如,您可以为每个线程提供对相同 BlockingQueue 的引用,并以此方式发送消息。

任何public静态字段都是全局可见的,因此任何线程都可以通过这样的字段访问诸如队列之类的共享对象。

想到的与 JVM 的“内置”最接近的是系统属性;本质上,这是一个共享映射,任何线程都可以通过它设置或获取 String 类型的条目。可能还有其他一些设施可能会以类似的方式被滥用,但我想不出有什么理由在静态字段服务时使用这样的东西。

您在标题中提问:

Is there a way to communicate between two completely independent threads?

(a) JVM 中的线程永远不会“完全独立”,因为线程共享 JVM 的资源和约束。

(b) 是的,object 可以通过多种方式在线程内或跨线程进行通信。

您在评论中提问:

is there an instance of such an object, created at startup by the JVM and to which all running threads could easily grab a reference to ?

线程不获取对 objects 的引用,线程中的 objects 执行方法获取引用。

JVM 启动时有许多 object 可用。例如,System.out。在任何线程中执行的任何 object 都可以访问此类 objects.

Frameworks 提供额外的 objects 以在线程之间共享。例如,Jakarta Servlet 框架提供了一个 ServletContext 的实例,表示用于所有线程处理请求的 Web 应用程序。

但您需要的解决方案可能非常简单:传递所需的 object。 当实例化 RunnableCallable object要在线程内执行,将需要的资源传递给构造函数。与其考虑“获取”全局 object,不如考虑“被递交”需要 objects.

在此示例中,我们创建了 Runnable class CounterRunnable task1Runnable task2 的两个实例。对于每个实例,我们传递一个共享资源,一个 AtomicInteger 实例。 Atomic… 意味着 object 在内部是 thread-safe,因此我们可以安全地跨线程操作单个实例。

package work.basil.threading;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class App {
    public static void main ( String[] args ) {
        App app = new App();
        app.demo();
    }

    private void demo () {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool( 3 );
        AtomicInteger count = new AtomicInteger( 0 );  // Shared object.
        Runnable task1 = new Counter( count );  // ⟸ Pass shared object to constructor of each `Runnable`/`Callable`. 
        Runnable task2 = new Counter( count );
        scheduledExecutorService.scheduleAtFixedRate( task1 , 0 , 5 , TimeUnit.SECONDS );
        scheduledExecutorService.scheduleAtFixedRate( task2 , 0 , 7 , TimeUnit.SECONDS );

        try { Thread.sleep( Duration.ofSeconds( 40 ).toMillis() ); } catch ( InterruptedException e ) { e.printStackTrace(); }
        scheduledExecutorService.shutdown();
        try { scheduledExecutorService.awaitTermination( 5 , TimeUnit.SECONDS ); } catch ( InterruptedException e ) { e.printStackTrace(); }
        System.out.println( "count = " + count );
    }

    class Counter implements Runnable {
        AtomicInteger countingTracker;

        public Counter ( AtomicInteger countingTracker ) {
            this.countingTracker = countingTracker;
        }

        @Override
        public void run () {
            Instant instant = Instant.now();
            int currentCount = this.countingTracker.incrementAndGet();
            System.out.println( "`Counter` object in thread " + Thread.currentThread().getId() + " set this.countingTracker to: " + currentCount + " at " + instant + "." );
        }
    }
}

System.out object 不一定按时间顺序报告。如您所见,第二个事件先于第一个事件出现在控制台上。因此,请关注 Instant 时刻以查看事件的真实顺序。

`Counter` object in thread 16 set this.countingTracker to: 2 at 2021-08-06T16:34:02.460073Z.
`Counter` object in thread 15 set this.countingTracker to: 1 at 2021-08-06T16:34:02.459625Z.
`Counter` object in thread 15 set this.countingTracker to: 3 at 2021-08-06T16:34:07.463863Z.
`Counter` object in thread 16 set this.countingTracker to: 4 at 2021-08-06T16:34:09.463869Z.
`Counter` object in thread 17 set this.countingTracker to: 5 at 2021-08-06T16:34:12.459813Z.
`Counter` object in thread 15 set this.countingTracker to: 6 at 2021-08-06T16:34:16.460429Z.
`Counter` object in thread 16 set this.countingTracker to: 7 at 2021-08-06T16:34:17.463699Z.
`Counter` object in thread 16 set this.countingTracker to: 8 at 2021-08-06T16:34:22.463406Z.
`Counter` object in thread 17 set this.countingTracker to: 9 at 2021-08-06T16:34:23.463713Z.
`Counter` object in thread 15 set this.countingTracker to: 10 at 2021-08-06T16:34:27.463391Z.
`Counter` object in thread 16 set this.countingTracker to: 11 at 2021-08-06T16:34:30.463637Z.
`Counter` object in thread 17 set this.countingTracker to: 12 at 2021-08-06T16:34:32.463385Z.
`Counter` object in thread 17 set this.countingTracker to: 13 at 2021-08-06T16:34:37.463273Z.
`Counter` object in thread 15 set this.countingTracker to: 14 at 2021-08-06T16:34:37.463329Z.
`Counter` object in thread 17 set this.countingTracker to: 15 at 2021-08-06T16:34:42.463201Z.
count = 15

你问过:

I am trying to communicate between two threads

一个解决方案是用thread-safe消息queue替换Runnableobject跨线程共享的AtomicIntegerobjectobject,如Answer by erickson.

所述