问题引出
假如说你的服务器在很短时间内承受了大量的客户端请求(如果这是你朋友用Python搞你的话请好好打他一顿),客户端请求量可能超过了服务器本身的即时处理量,而服务端程序又不能丢弃任何一个客户请求,应该怎么办?
答:最佳处理方案莫过于让客户端排队请求进行排队,由服务端程序一个个处理。这样既保证了所有的客户端请求均不丢失,同时也避免了服务器由于同时处理太多的请求而崩溃。这就是Guarded Suspension模式
Guarded Suspension模式
Guarded是“被保护着的”、“被防卫着的”意思,Suspension则是“暂停”的意思。
Guarded Suspension意为保护暂停,其核心思想是仅当服务进程准备好时,才提供服务。
角色 | 作用 |
---|---|
Request | 表示客户端请求 |
RequestQueue | 用于保存客户端的请求的队列,充当中间缓存,由ClientThread和ServerThread 共同维护 |
ClientThread | 客户端进程,用于发送请求并把请求对象放入请求队列 |
ServerThread | 服务器进程,根据自身状态,在有能力处理请求时,从请求队列中提取请求对象加以处理 |
// 一个POJO对象,封装了请求的内容
public class Request {
private String name;
public Request(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Request{" +
"name='" + name + '\'' +
'}';
}
}
// Request的集合,维护系统的Request请求列表
public class RequestQueue {
private LinkedList queue = new LinkedList();
public synchronized Request getRequest() {
while (queue.size() == 0) {
try {
wait(); // 等待直到有新的Request加入
} catch (InterruptedException e) {
}
}
return (Request)queue.remove(); // 返回Request队列中的第一个请求
}
public synchronized void addRequest(Request request) {
queue.add(request); // 加入新的Request请求
notifyAll(); // 通知getRequest()方法
}
}
// 服务端进程代码,用于处理用户的请求操作
public class ServerThread extends Thread {
private RequestQueue requestQueue; // 请求队列
public ServerThread(RequestQueue requestQueue, String name) {
super(name);
this.requestQueue = requestQueue;
}
@Override
public void run() {
while (true) {
final Request request = requestQueue.getRequest(); // 得到请求
try {
Thread.sleep(100); // 模拟请求处理耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " handles " + request);
}
}
}
// 客户端的请求发起进程
public class ClientThread extends Thread {
private RequestQueue requestQueue; // 请求队列
public ClientThread(RequestQueue requestQueue, String name) {
super(name);
this.requestQueue = requestQueue;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Request request = new Request("RequestID:" + i + " Thread_Name:" + Thread.currentThread().getName()); // 构造请求
System.out.println(Thread.currentThread().getName() + " requests " + request);
requestQueue.addRequest(request); // 提交请求
try {
Thread.sleep(10); // 模拟客户端请求的速度,快于服务端处理速度
} catch (InterruptedException e) {
}
System.out.println("ClientThread Name is:" + Thread.currentThread().getName());
}
System.out.println(Thread.currentThread().getName() + " request end");
}
}
// 主函数
public class Main {
public static void main(String[] args) {
RequestQueue requestQueue = new RequestQueue();
for (int i = 0; i < 10; i++) {
new ServerThread(requestQueue, "ServerThread" + i).start();
}
for (int i = 0; i < 10;i++) {
new ClientThread(requestQueue, "ClientThread" + i).start();
}
}
}
分析
开启了10个Client和Server进程,每个Client进程发送10个请求。由于Client进程的请求速度快于Server的处理速度,因此RequestQueue起到了中间缓存作用。当所有Client进程结束后,Server进程并没有停止工作,而是继续处理RequestQueue的请求,直至所有Request请求均得到处理
扩展——携带返回结果的Guarded Suspension
未完待续。。。