是否有一个非线程替代 运行 对象并发或 运行 永不结束循环而不阻塞主线程?

Is there a non-Thread alternative to run objects concurrently or to run never ending loop without blocking the main thread?

我的目标是同时 运行 多个对象,而不会由于可伸缩性问题而创建新线程。其中一种用法是 运行建立一个保持活动的套接字连接。

while (true) {
  final Socket socket = serverSocket.accept();
  final Thread thread = new Thread(new SessionHandler(socket)).start();
  // this will become a problem when there are 1000 threads.
  // I am looking for alternative to mimic the `start()` of Thread without creating new Thread for each SessionHandler object.
}

为简洁起见,我将使用 Printer anology。

我尝试过的:

  1. 使用CompletableFuture,检查后,使用ForkJoinPool是一个线程池

我认为可行的方法:

  1. 演员模型。老实说,这个概念今天对我来说是新的,我仍在弄清楚如何 运行 对象方法而不阻塞主线程。

main/java/SlowPrinter.java

public class SlowPrinter {
  private static final Logger logger = LoggerFactory.getLogger(SlowPrinter.class);

  void print(String message) {
    try {
      Thread.sleep(100);
    } catch (InterruptedException ignored) {
    }
    logger.debug(message);
  }
}

main/java/NeverEndingPrinter.java

public class NeverEndingPrinter implements Runnable {
  private final SlowPrinter printer;

  public NeverEndingPrinter(SlowPrinter printer) {
    this.printer = printer;
  }

  @Override
  public void run() {
    while (true) {
      printer.print(Thread.currentThread().getName());
    }
  }
}

test/java/NeverEndingPrinterTest.java

  @Test
  void withThread() {
    SlowPrinter slowPrinter = new SlowPrinter();
    NeverEndingPrinter neverEndingPrinter = new NeverEndingPrinter(slowPrinter);
    Thread thread1 = new Thread(neverEndingPrinter);
    Thread thread2 = new Thread(neverEndingPrinter);
    thread1.start();
    thread2.start();

    try {
      Thread.sleep(1000);
    } catch (InterruptedException ignored) {
    }
  }

目前,创建新线程是我所知道的唯一解决方案。但是,当有 1000 个线程时,这就成了问题。

您正在寻找 ScheduledExecutorService

创建一个初始 ScheduledExecutorService 具有固定适当数量的线程,例如Executors.newScheduledThreadPool(5) 5 个线程,然后您可以安排一个重复性任务,例如service.scheduleAtFixedRate(task, initialDelay, delayPeriod, timeUnit).

当然这样内部会用到线程,但是不会有你关心的上千线程的问题

过去很多开发者想出的解决方案就是ThreadPool。它通过重用相同的有限线程集避免了创建许多线程的开销。

然而,它要求您将工作分成小部分,并且您必须 link 一步一步地执行工作流程,否则您将在单独的单个方法中执行这些工作线。这就是 CompletableFuture 的结果。

Actor 模型是一种更奇特的建模技术,用于在流程中分配单独的步骤,但它们将再次在有限数量的线程上执行,通常每个 actor 仅 1 或 2 个。

有关以这种方式解决的问题的非常好的理论解释,请参阅 https://en.wikipedia.org/wiki/Staged_event-driven_architecture

如果我回顾一下您原来的问题,您的问题是您希望从多个来源接收保持活动消息,并且不想为每个来源使用单独的线程。

如果您使用像 while (socket.getInputStream().read() != -1) {} 这样的阻塞 IO,您将始终需要每个连接一个线程,因为该实现会在等待数据时让线程休眠,因此线程在此期间不能做任何其他事情。

相反,您真的应该研究一下 NIO。您只需要 1 个选择器和 1 个线程,您可以在其中连续检查选择器是否有来自任何来源的传入消息(不阻塞线程),并使用类似 HashMap 的东西来跟踪哪个来源仍在发送消息。

另见

NIO API 非常底层,顺便说一句,所以使用像 Netty 这样的框架可能更容易上手。