在直接使用创建线程Thread-Per-Message模式中,每次都会创建新线程导致占用了大量的系统资源,在占用过多的资源后可能导致OOM,于是就需要一种Work Thread模式的出现,导致出现了线程池的思想

对应到现实生活中,就可以类比为一个工厂中,多个工人去干活,有活一起干,没活聊聊天,在编程领域和现实领域中,工人的数量都是一定的

图片

那么线程池就是基于这种思想进行的创建,为了避免线程的创建和销毁导致的占用性能过高

将线程放在一个对象池中进行了保护起来,接下来就是利用这个线程池去解决之前的echo问题

仅仅是将线程改为从线程池之中获取,然后进行任务的提交处理

ExecutorService es = Executors.newFixedThreadPool(500);

final ServerSocketChannel ssc = ServerSocketChannel.open().bind(new InetSocketAddress(8080));

//处理请求

try {

while (true) {

// 接收请求

SocketChannel sc = ssc.accept();

// 将请求处理任务提交给线程池

es.execute(()->{

try {

// 读Socket

ByteBuffer rb = ByteBuffer.allocateDirect(1024);

sc.read(rb);

//模拟处理请求

Thread.sleep(2000);

// 写Socket

ByteBuffer wb =

(ByteBuffer)rb.flip();

sc.write(wb);

// 关闭Socket

sc.close();

}catch(Exception e){

throw new UncheckedIOException(e);

}

});

}

} finally {

ssc.close();

es.shutdown();

}

同时,在使用线程池的时候,为了避免无限制的创建线程导致OOM,避免无限制的接受任务导致OOM,一定要创建有界的队列来接受任务,避免OOM问题的出现,同时,在使用了有界的队列之后,需要制定明确的拒绝策略

最好在线程的工厂中制定相对应的线程名字,方便去查询业务相关的信息

其次,是为了避免线程死锁,一定要一个线程池对应一个任务,如果多个任务之间具有等待关系,一定要用多个线程池,不然,可能导致所有的线程都被用来等待了,没有真正去运行任务

这个模式和Thread-Per-Message模式之间最大的区别在于,直接使用一个线程去异步执行请求,我们是知道是谁去做的,但是使用线程池去执行一个请求,那么就无法知道具体是谁去做的

发表评论

邮箱地址不会被公开。 必填项已用*标注