基于不同任务执行策略的 Web 服务器

基于不同任务执行方式的 Web 服务器

任务执行策略一文中,简单介绍了 Java 常见的三种任务执行策略及其优缺点。本文将介绍分别基于这三种任务执行策略的服务器的特点,以说明在特定的场景中,合适的任务执行策略的重要性。

单线程 Web 服务器

该例程是一个串行的 Web 服务器,该服务器每次只能接受一个请求,主线程在接受连接和处理相关请求等操作间不断地交替运行,该策略使得服务器资源利用率低,无法提供高吞吐率或快速响应性。

public class SingleThreadWebServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(80);
        while (true) {
            Socket conncetion = serverSocket.accept();
            handleRequest(conncetion);
        }
    }
   
    private static void handleRequest(Socket connection) { }
}
多线程 Web 服务器

和 SingleThreadWebServer 相比,该服务器程序为每个请求产生一个新的线程,以支持并行处理多个请求。

负载在服务器可承受的前提下,该策略可以得到更快的响应性和更高的吞吐量。但这种无限创建线程的方式依然有许多缺陷:

  1. 线程生命周期的开销非常高
  2. 线程的创建和销毁需要一定开销,如果请求的到达率非常高而请求的处理过程是轻量级的(大多数服务器都是这样), 那么线程的生命周期将消耗大量计算资源。
  3. 资源消耗严重:活跃线程会消耗系统资源,尤其是内存。若可运行的线程数量多于可用的处理器数量,那么有些线程将被闲置,而闲置线程依然会占用内存资源,给 GC 更大的压力。且大量线程竞争 CPU 时,也会带来额外开销。线程数量只要能保证 CPU 一直处于忙碌状态即可,更多的线程反而会降低性能。
  4. 影响服务器稳定性:无限膨胀的线程数极可能突破平台的限制(JVM、操作系统等),并引发难以恢复的异常,会影响程序的稳定性。
public class ThreadPerTaskWebServer {
    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (true) {
            final Socket connection = socket.accept();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    handleRequest(connection);
                }
            };
            new Thread(runnable).start();
        }
    }
    private static void handleRequest(Socket connection) {}
}
基于 Executor 的 Web 服务器

本服务器使用 Executor 将用户请求任务的提交和任务的实际执行解耦开来,且只需要使用另一种 Executor 实现就可以改变任务执行策略。将 Executor 的实现替换成 ThreadPerTaskWebServer、SingleThreadWebServer,很容易模拟ThreadPerTaskWebServer、SingleThreadWebServer 的行为。

使用基于 newFixedThreadPool 实现的 Executor 作为 Web 服务器任务执行的策略,可以在节约线程创建、销毁带来的开销的同时,避免服务器产生过多的线程从而影响服务器性能。

public class TaskExecutionWebServer {
    private static final int NTHREADS = 100;
    private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(80);
        while (true) {
            final Socket connection = serverSocket.accept();
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    handleRequest(connection);
                }
            };
            exec.execute(task);
        }
    }

    private static void handleRequest(Socket connection) { }
}
/**
 * 服务器行为类似于 ThreadPerTaskWebServer,为每个请求分配一个线程
 */
class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        new Thread(r).start();
    }
}

/**
 * 服务器行为类似于 SingleThreadWebServer,以同步的方式执行任务
 */
class WithinThreadExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值