使用Java虚拟线程开发一个Web服务器可以显著提升并发能力,同时保持代码简洁。在这个示例中,我们将使用 Java 21 的虚拟线程实现一个简单的 HTTP Web 服务器,逐步解释每个部分的代码。
实现目标
- 通过虚拟线程处理 HTTP 请求。
- 创建一个简单的 Web 服务器来响应客户端请求。
- 适配 IO 阻塞的情况,让每个请求独占一个虚拟线程。
代码示例:Web服务器的实现
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
public class VirtualThreadHttpServer {
public static void main(String[] args) throws IOException {
// 1. 创建 HTTP 服务器,绑定到本地端口 8080
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
// 2. 注册 HTTP 处理程序(Handler),处理 "/hello" 路径
server.createContext("/hello", new HelloHandler());
// 3. 设置线程池,使用虚拟线程处理每个请求
server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
// 4. 启动服务器
server.start();
System.out.println("Server is listening on http://localhost:8080...");
}
// 处理 HTTP 请求的 Handler
static class HelloHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
// 5. 设置响应头和响应体内容
String response = "Hello, Virtual Threads!";
exchange.sendResponseHeaders(200, response.getBytes().length);
// 6. 将响应内容写入输出流并关闭流
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
}
代码讲解
-
创建 HTTP 服务器:
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
这里我们使用
com.sun.net.httpserver.HttpServer
创建一个 HTTP 服务器,并绑定到localhost:8080
端口。第二个参数0
表示允许的连接队列大小为默认值。 -
注册请求处理程序(Handler):
server.createContext("/hello", new HelloHandler());
我们通过
createContext
注册一个路径为/hello
的处理器。当客户端访问该路径时,会触发对应的处理逻辑。 -
使用虚拟线程池:
server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
在这里,我们使用了 虚拟线程池 来处理每个 HTTP 请求。
newVirtualThreadPerTaskExecutor
是 Java 提供的一个工厂方法,能够为每个任务创建一个新的虚拟线程。 -
启动服务器:
server.start();
服务器启动后,将开始监听客户端的 HTTP 请求。
-
处理 HTTP 请求:
String response = "Hello, Virtual Threads!"; exchange.sendResponseHeaders(200, response.getBytes().length);
这里我们定义了一个简单的响应消息
"Hello, Virtual Threads!"
,并通过sendResponseHeaders
发送状态码200
和响应内容长度。 -
输出响应内容并关闭流:
try (OutputStream os = exchange.getResponseBody()) { os.write(response.getBytes()); }
将响应内容写入
HttpExchange
的输出流,并在完成后自动关闭流。
如何运行
- 确保你使用的是 Java 21 及以上版本。
- 将上述代码保存为
VirtualThreadHttpServer.java
。 - 编译并运行:
javac VirtualThreadHttpServer.java java VirtualThreadHttpServer
- 打开浏览器访问:
http://localhost:8080/hello
,你会看到如下输出:Hello, Virtual Threads!
虚拟线程的优势
- 处理大量并发请求:每个请求都有自己的虚拟线程,避免了传统线程池的限制,支持上万甚至更多的并发连接。
- 简化代码:通过虚拟线程,异步逻辑可以用同步的方式编写,无需复杂的回调或
CompletableFuture
。 - 低资源消耗:虚拟线程非常轻量级,不会像系统线程一样占用大量内存。
扩展功能建议
- 日志记录:添加请求日志,记录每次访问的路径和时间。
- 异步数据库访问:处理请求时查询数据库并返回结果。
- REST API:实现更多的 HTTP 处理程序来支持不同的 REST API 请求。
这个示例展示了虚拟线程如何简化 Web 服务器的开发,并在高并发场景下提供优异的性能。