第四部分 服务器的工作模式

本文介绍了一种使用线程池处理客户端请求的方法,并通过两个实例演示了线程池的基本操作及状态管理,包括线程调度、状态变更等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在网络服务器一般工作在多线程模式下,主线程负责侦听和接入来自客户端的链接请求,在收到一个连接请求之后转交给另一个线程进行处理,自身继续返回侦听状态。

在如何处理客户端请求方面,有两种选择:1。每当收到请求之后实时地创建一个新线程;2。在服务器启动时便预先创建一批线程,这些线程在空闲时处于等待状态,当接入到一个新请求后,服务器从这些线程中唤醒一个,使其成为工作线程,处理接入的请求。

就第一种来说,创建线程需要消耗一定的资源,具有潜在的不稳定因素。在需要时才创建线程,为服务器整体稳定性带来了隐患。好处是所能响应的客户端请求的数量仅受服务器性能的制约,在服务器能承受的范围之内,都能创建新线程处理客户端的请求。

第二种方式也成为线程池方式。优势是响应请求的速度快,因为工作线程在服务器启动之初便已创建完毕,在需要时只需从线程池中取出即可。

线程池一

下面实例充分的演示线程池的作用,突出线程池处理短请求的特点。客户端请求非常短,只要求服务器从线程池中调度处一个线程,将客户端传给服务器的字符串输出在控制台上。

客户端代码【Commander

/** * Commander.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午05:24:45 */ package com.cayden.thread822; import java.io.PrintWriter; import java.net.Socket; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class Commander { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Socket socket=null; PrintWriter out=null; try{ socket=new Socket("127.0.0.1",1024); out=new PrintWriter(socket.getOutputStream(),true); byte[] b=new byte[2048]; String msg=new String(b,0,System.in.read(b)); while(!msg.startsWith("stop")){ out.println(msg); msg=new String(b,0,System.in.read(b)); } out.println(msg); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally{ try{ if(socket!=null){ socket.close(); } }catch (Exception e) { // TODO: handle exception } } } }

服务器端代码【ThreadManager

/** * ThreadManager.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午05:31:48 */ package com.cayden.thread822; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class ThreadManager { TheThread[] runner=null; int count; public ThreadManager(int count){ this.count=count; } boolean busy; public void listen() throws IOException { //建立线程池,启动所有线程 runner=new TheThread[this.count]; for(int i=0;i<this.count;i++){ runner[i]=new TheThread(i); runner[i].start(); } //侦听1024端口 ServerSocket serverSocket=new ServerSocket(1024); Socket socket=serverSocket.accept(); while(true){ try{ BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); String cmd=in.readLine(); if(cmd==null) break; if(cmd.startsWith("stop")) { for(int i=0;i<5;i++){ synchronized (runner[i]) { Thread.sleep(500); runner[i].interrupt(); } } System.out.println("线程池已被销毁,程序退出"); break; }else{ synchronized (this) { busy=true; for(int i=0;i<5;i++){ if(runner[i].string==null){ runner[i].string=cmd; busy=false; break; } } if(busy) System.out.println("服务器正忙,线程池中没有空闲线程处理指令:"+cmd); } } }catch (Exception e) { // TODO: handle exception } } } /** * @param args */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub new ThreadManager(5).listen(); } } class TheThread extends Thread{ int no; public String string=null; public TheThread(int i){ this.no=i; } public void run(){ try{ while(true){ Thread.sleep(1000); if(this.string!=null) synchronized (this) { System.out.println("第"+no+"个线程处理指令:"+this.string); this.string=null; } } }catch (InterruptedException e) { // TODO: handle exception System.out.println("["+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"] "+"线程"+this.no+"被终止..."); } } }

运行结果如下:

客户端控制台:

1 2 3 stop

服务端控制台:

第0个线程处理指令:1 第0个线程处理指令:2 第0个线程处理指令:3 [2011-01-19 14:33:56] 线程0被终止... [2011-01-19 14:33:56] 线程1被终止... [2011-01-19 14:33:57] 线程2被终止... [2011-01-19 14:33:57] 线程3被终止... 线程池已被销毁,程序退出 [2011-01-19 14:33:58] 线程4被终止...

线程池二

本实例演示线程池状态的管理。服务器根据客户端输入的以下指令调度池中的线程。

lreport:报告目前线程池中有几个线程处于运行状态。

lpause:线程池中的全部线程进入等待状态。

lstep:唤醒处于等待状态的线程中的一个,如果没有任何线程处于等待状态,则不起任何作用。

lrun:唤醒全部处于等待状态的线程,如果没有任何线程处于等待状态,则不起任何作用。

lstop:终止全部线程,销毁线程池。

客户端的代码和上面的一样,服务端代码如下:【ThreadManager2

/** * ThreadManager2.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-14 上午09:07:56 */ package com.cayden.thread822; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class ThreadManager2 { TheThread2[] runner=null; int count; public ThreadManager2(int count){ this.count=count; } private void listen() throws Exception{ //建立线程池,启动所有线程 runner=new TheThread2[this.count]; for(int i=0;i<this.count;i++){ runner[i]=new TheThread2(i); runner[i].start(); } //侦听1024端口 ServerSocket serverSocket=new ServerSocket(1024); while(true){ final Socket socket=serverSocket.accept(); Thread worker=new Thread(){ public void run(){ while(true){ try{ BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); String cmd=in.readLine(); if(cmd==null) break; System.out.println("收到命令:"+cmd); if(cmd.startsWith("run")){ for(int i=0;i<5;i++){ synchronized (runner[i]) { runner[i].notify(); runner[i].command=0; runner[i].status=1; } } } if(cmd.startsWith("pause")){ for(int i=0;i<5;i++){ synchronized (runner[i]) { runner[i].command=1; } } } if(cmd.startsWith("step")){ for(int i=0;i<5;i++){ synchronized (runner[i]) { if(runner[i].status==0){ runner[i].notify(); runner[i].command=0; runner[i].status=1; break; } } } } if(cmd.startsWith("report")){ System.out.print("线程池中共有5个线程,"); int workingThreadCount=0; for(int i=0;i<5;i++) if(runner[i].status==1) workingThreadCount++; System.out.println("其中"+workingThreadCount+"个线程处于工作状态"); } if(cmd.startsWith("stop")){ for(int i=0;i<5;i++){ synchronized (runner[i]) { Thread.sleep(500); runner[i].interrupt(); } } System.out.println("线程池已被销毁,程序退出"); break; } }catch (Exception e) { // TODO: handle exception } } } }; worker.start(); } } /** * @param args */ public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub new ThreadManager2(5).listen(); } } class TheThread2 extends Thread{ int no; int command=0; int status;//0空闲中 1:运行中。 public TheThread2(int i){ this.no=i; } public void run(){ try{ while(true){ Thread.sleep(1000); if(this.command==1) synchronized (this) { System.out.println("["+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"] "+"线程"+this.no+"开始等待..."); this.status=0; this.wait(); } } }catch (InterruptedException e) { // TODO: handle exception System.out.println("["+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"] "+"线程"+this.no+"被终止..."); } } }

客户端运行结果如下:

report pause run report step report step pause report stop

服务端运行结果如下:

收到命令:report 线程池中共有5个线程,其中0个线程处于工作状态 收到命令:pause [2011-01-19 14:41:51] 线程1开始等待... [2011-01-19 14:41:51] 线程0开始等待... [2011-01-19 14:41:51] 线程3开始等待... [2011-01-19 14:41:51] 线程2开始等待... [2011-01-19 14:41:51] 线程4开始等待... 收到命令:run 收到命令:report 线程池中共有5个线程,其中5个线程处于工作状态 收到命令:step 收到命令:report 线程池中共有5个线程,其中5个线程处于工作状态 收到命令:step 收到命令:pause [2011-01-19 14:42:36] 线程0开始等待... [2011-01-19 14:42:36] 线程4开始等待... [2011-01-19 14:42:36] 线程3开始等待... [2011-01-19 14:42:36] 线程2开始等待... [2011-01-19 14:42:36] 线程1开始等待... 收到命令:report 线程池中共有5个线程,其中0个线程处于工作状态 收到命令:stop [2011-01-19 14:42:57] 线程0被终止... [2011-01-19 14:42:57] 线程1被终止... [2011-01-19 14:42:58] 线程2被终止... [2011-01-19 14:42:58] 线程3被终止... 线程池已被销毁,程序退出 [2011-01-19 14:42:59] 线程4被终止...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值