【问题标题】:Why Java Socket doesn't support interruption handling?为什么 Java Socket 不支持中断处理?
【发布时间】:2018-07-29 16:50:08
【问题描述】:

我一直在思考为什么 JDBC 只是阻塞操作以及为什么我不能为假设的事件处理程序 onResultSetArrived(ResultSet rs) 设置一些侦听器。为什么我必须为每个 JDBC 查询阻塞一个线程。

一段时间后,我深入研究了 Java 套接字(我想 JDBC 是建立在它们之上的),并意识到也没有任何事件处理。提供非阻塞读取的唯一选项是通过 available() 方法,但这非常低效,因为它必须在循环中定期检查。

据我所知,中断是 PC 中的基本功能。它从硬件到操作系统。在Java中,它可以实现为从Socket读取值的事件驱动方法。

现在,我的问题是我是否遗漏了什么并且存在一些解决方法或 Java 中的当前架构真的是 每个阻塞操作一个线程? 如果是,则不是'效率低吗?

【问题讨论】:

  • “Java 中的当前架构确实是每个阻塞操作一个线程” - 对于阻塞 I/O,是的。然而,Project Loom 正在将 Fibers 和 Continuations 引入 Java,这将使其大大更有效率:)

标签: java


【解决方案1】:

在 Java 中,您可以拥有多个线程。一个线程一直在做它的事情,直到它在某个地方被阻塞(通常是在互斥锁或 I/O 操作上)。当然,这不会阻塞其他线程。

多线程应用程序的基本场景是您使用多个线程时等待阻塞的线程会引入过多的等待。此处“太多”的定义完全取决于您,但总的来说,这就是您如何通过更好地利用资源来获得更好的性能。

但是,Java 中线程的工作方式存在一些限制。大多数(如果不是全部的话)是当线程在Java“外部”的某个地方被阻塞时,例如在操作系统调用或外部(本机)库中。理论上,如果本机代码阻塞了一个线程,Java 对此无能为力。通常,除非本机代码有错误,否则这应该不是问题。

因此,在阻塞 JDBC 响应的情况下,您将创建一个新线程,该线程将在第一个线程等待数据库完成时执行其他工作。或者,您可以创建一个仅用于执行 JDBC 的线程。除了操作系统施加的限制外,您可以完全按照您的意愿(使用侦听器等)。所以这是可能的,但它可能不是由 JDBC 驱动程序提供的。核心 Java 中已经有很多基础设施,您可能会发现它们很有用(线程池、工作线程、同步集合)。但与任何多线程一样,您需要非常小心地同时访问来自不同线程的数据。

从 Java 7 开始,还支持非阻塞 I/O (NIO)。这几乎正​​是您所描述的。 I/O 被卸载到操作系统,因此您的操作会立即返回,并且在操作完成时您会收到回调。但是,并非所有库都支持 NIO。对于我的工作,我从来没有理由使用它,因为我总是可以用我的线程实现相同的东西,至少同样好。

【讨论】:

  • 据我所知,一个线程意味着立即消耗 1MB 内存(在 32 位上为 512kb)。因此,如果您一次有 1000 个请求,并且每个请求将以异步方式运行,消耗另外 6 个线程,即使这些线程由于等待某些阻塞操作而处于空闲状态,也会消耗 6000MB 的 RAM。您可以只使用 1 个线程来处理此请求,但您有 6000 个线程。而且我不是线程专家,但是性能呢?必须在这么多线程之间切换。
  • 当然,切换线程会产生一些开销,但这在任何情况下都是不可避免的。一般规则是使用尽可能少的线程。在 JDBC 的情况下,线程数过多不太可能带来任何额外的性能改进。最好的方法是创建一个工作池和一个从池中获取工作的线程池。如果你正确地实现它们,这种异步机制会非常有效。
  • 为什么 JDBC 的线程越少越好?如果一个对 DB 的请求将花费 200ms 秒,因为 DB 在另一台服务器上并且存在一些延迟,那么您需要大量线程并且大部分时间都处于阻塞状态。我认为Java没有任何借口。当前的架构已经过时了,仅此而已。 Oracle 中有一些 ADBA movenet 应该提供 JDBC 的异步变体,但现在是 2018 年,它还没有完成!!!
  • 我想我不够清楚。您希望线程数与有用的工作相匹配——不是更少,也不是更多。但是这里还有很多事情需要考虑。简而言之,我在 Java 中看到了很多架构限制,但我不会说这是其中之一。您可以自己实现一个非常有效的解决方案 - 所以限制是您缺乏知识,而不是 Java。
  • 嗯,你说得对,我缺乏知识,但我很清楚,无论有人开发什么解决方案,对于在 JDBC 中缺乏异步的 Java,它仍然是一种解决方法。
【解决方案2】:

如果问题是“Java 中的当前架构是否真的是每个阻塞操作一个线程”并且“阻塞操作”是指“数据库操作”,那么答案是否定的。目前可用于 Java 的大多数数据库驱动程序都是基于 jdbc 的,并且以这种方式工作。但是还有可用的替代品 (https://spring.io/blog/2016/11/28/going-reactive-with-spring-data) 以及更多的替代品( https://blogs.oracle.com/java/jdbc-next:-a-new-asynchronous-api-for-connecting-to-a-databasehttps://dzone.com/articles/spring-5-webflux-and-jdbc-to-block-or-not-to-block)。有关其工作原理,请参阅How is ReactiveMongo implemented so that it is considered non-blocking?

对于 jdbc,还有一些方法可以包装 jdbc 调用(Wrapping blocking I/O in project reactorSpring webflux and reading from database)和采用这种方法的项目(https://dzone.com/articles/myth-asynchronous-jdbc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2016-10-23
    • 2012-12-29
    相关资源
    最近更新 更多