2023-分布式学习记录5
并发服务技术
本节介绍三种并发请求处理技术,即多线程、线程池、事件驱动,同时介绍部分使用 java 需要注意的东西。
线程
线程的定义及特点
- 不同的线程在逻辑上相互独立地并行地执行
- 每个的线程都拥有自己独立的运行上下文(Runtime Context),主要包括独立的内存栈(主要存放局部变量和函数参数)和独立的CPU寄存器状态。每个线程可以不受干扰的访问自己的局部变量
- 属于同一个进程的多个线程共享该进程的内存地址空间
- 每一个线程都有自己的“主函数”。线程启动后,其主函数开始执行;线程主函数执行完毕,线程的生命周期就结束了
Java 的线程对象
- Java 线程对象是对操作系统线程对象的一个封装
- 一个Java线程对象一般都是 Thread 类(JDK实现的基类)的子类。子类需要重载 run 函数,作为自己的线程主函数
基于多线程的并发服务技术
// 多线程 // 1. 重载 Thread 类 public class UDPThread extends Thread { DatagramSocket asocket = null; DatagramPacket request = null; public UDPThread(DatagramSocket asocket, DatagramPacket request) { this.asocket = asocket; this.request = request; } // 重载 run 函数 public void run() { try { // 创建数据报 DatagramPacket reply = new DatagramPacket(request.getData(), request.getLength(), request.getAddress(), request.getPort()); // 发送数据报 asocket.send(reply); } catch (SocketException e) { System.out.println("Socket: " + e.getMessage()); } catch (IOException e) { System.out.println("IO: " + e.getMessage()); } } } // 2. 遇到新任务时创建新线程进行处理 public class MultiThreadUDPServer { public static void main(String args[]) throws Exception { DatagramSocket aSocket = new DatagramSocket(6789); int count = 0; while (true) { byte[] buffer = new byte[1000]; DatagramPacket request = new DatagramPacket(buffer, buffer.length); // 接收数据 aSocket.receive(request); System.out.println("Message from Client: " + new String(request.getData())); count++; // 创建新线程 UDPThread serverThread = new UDPThread(aSocket, request); // 启动线程 serverThread.start(); } } }
// 多线程 // 1. 重载 Thread 类 public class UDPThread extends Thread { DatagramSocket asocket = null; DatagramPacket request = null; public UDPThread(DatagramSocket asocket, DatagramPacket request) { this.asocket = asocket; this.request = request; } // 重载 run 函数 public void run() { try { // 创建数据报 DatagramPacket reply = new DatagramPacket(request.getData(), request.getLength(), request.getAddress(), request.getPort()); // 发送数据报 asocket.send(reply); } catch (SocketException e) { System.out.println("Socket: " + e.getMessage()); } catch (IOException e) { System.out.println("IO: " + e.getMessage()); } } } // 2. 遇到新任务时创建新线程进行处理 public class MultiThreadUDPServer { public static void main(String args[]) throws Exception { DatagramSocket aSocket = new DatagramSocket(6789); int count = 0; while (true) { byte[] buffer = new byte[1000]; DatagramPacket request = new DatagramPacket(buffer, buffer.length); // 接收数据 aSocket.receive(request); System.out.println("Message from Client: " + new String(request.getData())); count++; // 创建新线程 UDPThread serverThread = new UDPThread(aSocket, request); // 启动线程 serverThread.start(); } } }
基于线程池的并发服务技术
// 线程池 public ThreadPoolExecutor(int corePoolSize, int maximunPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler); /* corePoolSize,核心线程数。 没有任务时,核心线程也一直存活;所需线程数小于核心线程数时,线程池也会创建新线程;设置allowCoreThreadTimeout=true时,核心线程会超时关闭 maximunPoolSize,最大线程数 当线程数=maxPoolSize,且任务队列已满,此时添加任务时会触发RejectedExecutionHandler进行处理 keepAliveTime,线程空闲时间 如果线程数>corePoolSize,且有线程空闲时间达到keepAliveTime时,线程会销毁,直到线程数量=corePoolSize;如果设置allowCoreThreadTimeout=true时,核心线程执行完任务也会销毁直到数量=0 workQueue,任务队列 */ public class ThreadPoolServer { public static void main(String[] args) throws Exception { // 创建线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5)); ServerSocket listenSocket = new ServerSocket(8189); // 创建监听端口 Socket socket = null; // 记录连接端口 int count = 0; System.out.println("Server listening at 8189"); while (true) { socket = listenSocket.accept(); // 从队列中获取端口 count++; // 计数 MyTask myTask = new MyTask(socket,count); // 建立新线程 executor.execute(myTask); // 执行 } } } class MyTask implements Runnable { private Socket socket = null; private int num = 0; public MyTask(Socket socket, int num) { this.socket = socket; this.num = num; } // 重载 run 函数 @Override public void run() { InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; OutputStream os = null; PrintWriter pw = null; try { is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr); os = socket.getOutputStream(); pw = new PrintWriter(os); String info = null; while ((info = br.readLine()) != null) { System.out.println("Thread" + num + ",Message from client:" + info); pw.println(info); pw.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (pw != null) pw.close(); if (os != null) os.close(); if (br != null) br.close(); if (isr != null) isr.close(); if (is != null) is.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }