伪异步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。同步队列是一个特殊的队列,它在任务提交时要求必须有一个线程准备好接收任务,否则提交任务的线程会被阻塞。同步队列适用于需要强制任务提交和执行之间的同步的场景。