在jdk1.5以前,java并没有nio的概念,对于上个例子中所讲的传统BIO,每一个客户端的每一个连接都会产生一个线程,久而久之,服务器端就会面临内存爆满的情况导致宕机。那么jdk1.5前,这个为题如何解决?
答案是使用伪异步IO,就是线程池+队列组合。
实现思路:对于服务端收到的每一个TCP连接,仍然创建一个线程,不过这个线程被一个线程池来管理:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class HandlerExecutorPool { private ExecutorService executor; public HandlerExecutorPool(int maxPoolSize, int queueSize){ this.executor = new ThreadPoolExecutor( Runtime.getRuntime().availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize)); } public void execute(Runnable task){ this.executor.execute(task); } }
举例:当客户端发来150个连接,对应服务器端创建150个线程,假设我们的线程池初始化8个核心线程,最大线程50个,有界队列ArrayBlockingQueue的大小为100个,那么当这150个线程来到时,首先被线程池的8个核心线程占用,接着的142个线程中的100个被放入有界队列,剩下的42个线程由于不超过最大线程数50个,线程池将再开启42个线程来处理。如果此时客户端在发起TCP连接,服务器端的线程将会被线程池直接拒绝。
这样做的好处是避免了线程数暴增,而是使用队列和线程池管理器来,将数量和处理速度始终控制在一个阀值之内,使得系统可以平稳运行。这种方式也叫做bio 2.0。