模仿Tomcat的BIO,NIO线程模型

简介:

模仿Tomcat的BIO模型,来一个消息,分配一个线程处理.
则主线程池代码如下
package com.guanjian;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**

  • Created by Administrator on 2018/7/10.
    */

public class ThreadPool {

private ExecutorService service;
private List<MessageTask> tasks;
private int fixedThreadNum = 0;
private List<String> messages;
private MessageHandler messageHandler;
public ThreadPool(int fixedThreadNum,List<String> messages,MessageHandler messageHandler) {
    this.fixedThreadNum = fixedThreadNum;
    this.messages = messages;
    this.messageHandler = messageHandler;
    service = Executors.newFixedThreadPool(fixedThreadNum);
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            shutdownGracefully(service);
        }
    });
}
public void shutdownGracefully(ExecutorService ThreadPool) {
    ShutdownPool.shutdownThreadPool(ThreadPool, "main-pool");
}

public void startup() {
    tasks = new ArrayList<>();
    MessageTask messageTask = (fixedThreadNum == 0 ? new SequentialMessageTask(messageHandler,messages) : new ConcurrentMessageTask(messageHandler,messages));
    for (String message:messages) {
        tasks.add(messageTask);
        service.execute(messageTask);
    }
}

}
它是通过线程数fixedThreadNum来区分使用哪种线程模型.
package com.guanjian;

/**

  • Created by Administrator on 2018/7/10.
    */

public interface MessageHandler {

public void execute(String message);

}
package com.guanjian;

/**

  • Created by Administrator on 2018/7/10.
    */

public class MessageHandlerImpl implements MessageHandler {

@Override
public void execute(String message) {
    System.out.println(message);
}

}
以上是消息处理器的接口和实现类
package com.guanjian;

import java.util.List;

/**

  • Created by Administrator on 2018/7/10.
    */

public abstract class MessageTask implements Runnable {

protected MessageHandler messageHandler;
protected  List<String> messages;

MessageTask(MessageHandler messageHandler,List<String> messages) {
    this.messageHandler = messageHandler;
    this.messages = messages;
}
@Override
public void run() {
    for (String message:messages) {
        handlerMessage(message);
    }
}
protected abstract void handlerMessage(String message);

}
消息任务抽象类实现了Runnable线程接口,以不同的子类来实现BIO,NIO线程模型,具体在抽象方法handlerMessage中实现.
package com.guanjian;

import java.util.List;

/**

  • Created by Administrator on 2018/7/10.
    */

public class SequentialMessageTask extends MessageTask {

SequentialMessageTask(MessageHandler messageHandler, List<String> messages) {
    super(messageHandler, messages);
}

@Override
protected void handlerMessage(String message) {
    messageHandler.execute(message);
}

}
BIO线程模型子类,通过主线程池来分配线程处理.
package com.guanjian;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**

  • Created by Administrator on 2018/7/10.
    */

public class ConcurrentMessageTask extends MessageTask {

private ExecutorService asyncService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
ConcurrentMessageTask(MessageHandler messageHandler, List<String> messages) {
    super(messageHandler, messages);
}

@Override
protected void handlerMessage(String message) {
    asyncService.submit(new Runnable() {
        @Override
        public void run() {
            messageHandler.execute(message);
        }
    });
}
protected void shutdown() {
    ShutdownPool.shutdownThreadPool(asyncService,"async-pool-" + Thread.currentThread().getId());
}

}
NIO线程模型,不再使用主线程池来分配线程,而是异步线程池,类比于Netty中的Worker线程池,从BOSS线程池中接管消息处理.
package com.guanjian;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**

  • Created by Administrator on 2018/7/10.
    */

public class ShutdownPool {

private static Logger log = LoggerFactory.getLogger(ThreadPool.class);
/**
 * 优雅关闭线程池
 * @param threadPool
 * @param alias
 */
public static void shutdownThreadPool(ExecutorService threadPool, String alias) {
    log.info("Start to shutdown the thead pool: {}", alias);

    threadPool.shutdown(); // 使新任务无法提交.
    try {
        // 等待未完成任务结束
        if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
            threadPool.shutdownNow(); // 取消当前执行的任务
            log.warn("Interrupt the worker, which may cause some task inconsistent. Please check the biz logs.");

            // 等待任务取消的响应
            if (!threadPool.awaitTermination(60, TimeUnit.SECONDS))
                log.error("Thread pool can't be shutdown even with interrupting worker threads, which may cause some task inconsistent. Please check the biz logs.");
        }
    } catch (InterruptedException ie) {
        // 重新取消当前线程进行中断
        threadPool.shutdownNow();
        log.error("The current server thread is interrupted when it is trying to stop the worker threads. This may leave an inconcistent state. Please check the biz logs.");

        // 保留中断状态
        Thread.currentThread().interrupt();
    }

    log.info("Finally shutdown the thead pool: {}", alias);
}

}
最后是线程池的优雅关闭,无论是主线程池还是异步线程池皆调用该方法实现优雅关闭.

以上只是模型代码,具体可替换成具体需要的业务代码来达到业务性能的提升.

相关文章
|
3月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
22天前
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
1月前
|
Java 应用服务中间件
面对海量网络请求,Tomcat线程池如何进行扩展?
【10月更文挑战第4天】本文详细探讨了Tomcat线程池相较于标准Java实用工具包(JUC)线程池的关键改进。首先,Tomcat线程池在启动时即预先创建全部核心线程,以应对启动初期的高并发请求。其次,通过重写阻塞队列的入队逻辑,Tomcat能够在任务数超过当前线程数但未达最大线程数时,及时创建非核心线程,而非等到队列满才行动。此外,Tomcat还引入了在拒绝策略触发后重新尝试入队的机制,以提高吞吐量。这些优化使得Tomcat线程池更适应IO密集型任务,有效提升了性能。
面对海量网络请求,Tomcat线程池如何进行扩展?
|
24天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
16 1
|
2月前
|
消息中间件 存储 NoSQL
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型 。
97 20
剖析 Redis List 消息队列的三种消费线程模型
|
1月前
|
Dubbo Java 应用服务中间件
剖析Tomcat线程池与JDK线程池的区别和联系!
剖析Tomcat线程池与JDK线程池的区别和联系!
105 0
剖析Tomcat线程池与JDK线程池的区别和联系!
|
1月前
|
NoSQL Redis 数据库
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
本文解释了Redis为什么采用单线程模型,以及为什么Redis单线程模型的效率和速度依然可以非常高,主要原因包括Redis操作主要访问内存、核心操作简单、单线程避免了线程竞争开销,以及使用了IO多路复用机制epoll。
47 0
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
|
1月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
1月前
|
消息中间件 NoSQL 关系型数据库
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
23 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1