JAVA IO 从零实践 (4.伪异步IO通信:引入线程池+任务队列)

伪异步IO

所谓的伪异步IO就是对之前的BIO同步阻塞进行一点点小小的改进,但是改进的不是很彻底

上一篇我们通过创建线程来实现多个客户端通信。
但是这样有一个严重的问题:
每次new 线程来处理,对IO有很大的损耗,爱再者万一线程数量越来也多,会导致线程栈溢出 最终导致宕机。

所以在上一篇的末尾 我们提出一个构想就是使用线程池来动态的管理线程。
这样更灵活 且有线程池来动态的限制线程的创建和销毁,不会出现线程栈溢出 最终导致宕机。
在这里插入图片描述

(如果时新手对线程池比较陌生 那么你可能需要先去补一下线程池的使用基础)


话不多说我们来改造一下 上一篇BIO中的多线程:

public class HandlerSocketPool {

    private ExecutorService executorService;

    public HandlerSocketPool(int maxThread, int queueSize){

        /***
         *  public ThreadPoolExecutor(
         *  int corePoolSize,
         *  int maximumPoolSize,
         *  long keepAliveTime,
         *  TimeUnit unit,
         *  BlockingQueue<Runnable> workQueue) {
         */
        executorService = new ThreadPoolExecutor(
                3,
                maxThread,
                120,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(queueSize));
    }

   public void execute(Runnable task){
        executorService.execute(task);
   }
}

将socket包装成一个任务类:

public class ServerRunnableTask implements Runnable{
    private Socket socket;

    public ServerRunnableTask(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));

            String msg;

            while((msg =bufferedReader.readLine())!= null){
                System.out.println("服务端按行读取接收到当前线程:"+ Thread.currentThread().getName()+":"+ msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


/**
 * 实现服务端同时接收多个客户端socket通信需求
 * */
public class Sever {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);

            HandlerSocketPool pool = new HandlerSocketPool(6,10);
            while (true) {
                Socket socket = serverSocket.accept();
                //new ServerThreadReader(socket).start();
                //优化之前的线程创建 将socket包装成任务对象 交给线程池
                Runnable task = new ServerRunnableTask(socket);
                pool.execute(task);
            }
        } catch (IOException e) {
             e.printStackTrace();
        }

    }
}


这里为了照顾新手 拓展一个细节
就是创建线程池的时候 第3个参数 我们选择了有界限队列

为什么选这个原因如下:

FIFO队列(First-In-First-Out):也称为无界队列(Unbounded Queue),例如LinkedListBlockingQueue。它是一个基本的队列实现,按照任务提交的顺序进行执行。如果任务提交速度超过线程池处理任务的速度,队列会不断增长,可能导致内存溢出。

有界队列(Bounded
Queue):例如ArrayBlockingQueue和LinkedBlockingQueue。这些队列有一个指定的容量限制,当队列达到容量限制时,继续提交任务会被阻塞,直到有空间可用。有界队列可以有效地控制任务提交速度,防止线程池过载,但在达到队列容量限制时,可能需要根据需求进行处理,例如拒绝任务或者执行特定的处理策略。

优先级队列(Priority
Queue):例如PriorityBlockingQueue。优先级队列根据任务的优先级进行排序,优先级高的任务会被优先执行。这种队列适用于希望根据任务的相对优先级来控制执行顺序的情况。

同步队列(Synchronous
Queue):例如SynchronousQueue。同步队列是一个特殊的队列,它在任务提交时要求必须有一个线程准备好接收任务,否则提交任务的线程会被阻塞。同步队列适用于需要强制任务提交和执行之间的同步的场景。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值