Guarded Suspension设计模式

1 要解决的问题

    Guarded Suspension(保护暂停),其核心思想是:仅当服务端进程准备好后,才提供服务。假设一种场景,服务器可能会在短时间内接收到大量的客户端请求,可能已经超过了服务器的负载,而服务器又不能随意丢弃任何一个用户的请求。此时,最佳的处理方案莫过于让客户端请求排队,由服务器一个一个的处理。这样,既保证了所有的客户端请求不会丢失,同时也避免了服务器由于同时处理太多请求而崩溃。

2 涉及的角色

(1)ServerThread:服务器线程。从请求队列中获取请求
(2)ClientThread:客户端线程。提交请求,将请求插入共享的请求队列。
(3)Request:表示客户端请求。
(4)RequestQueue:请求队列。由客户端和服务端共同维护。必须是线程安全的。

3 Guarded Suspension的结构

    
    从流程图可以看出,在频繁的客户端请求中,RequestQueue充当了中间缓存,存放了大量的未处理的请求,保证了客户请求不丢失,同时,也保护服务器不会收到大量的并发请求而崩溃。

4 代码实现

4.1 无返回值给客户端线程

(1)Request.java:
public class Request {
	private String name;
	public Request(String name) {
		// TODO Auto-generated constructor stub
		this.name=name;
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "Request:"+name;
	}
}
(2)ServerThread.java:
public class ServerThread extends Thread{
	private BlockingQueue<Request> queue;
	public ServerThread(BlockingQueue<Request> queue,String name) {
		// TODO Auto-generated constructor stub
		super(name);
		this.queue=queue;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			/**
			 * 如果当前队列为空,将会阻塞
			 * 其实这种存在缺点,因为一个线程只能处理一个请求,就会挂掉,
			 * 这里可以加上一个while(true)的循环,一直监听请求队列,即一个线程处理完一个请求后,
			 * 将会判断请求队列是否为空,如果为空则阻塞,不为空则继续处理
			 */
			Request request=queue.take();
			System.out.println("Master"+Thread.currentThread().getName()+"处理请求:"+request);
			/**
			 * 模拟耗时操作
			 */
			Thread.currentThread().sleep(1000);
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
(3)ClientThread.java:
public class ClientThread extends Thread{
	private BlockingQueue<Request> queue;
	public ClientThread(BlockingQueue<Request> queue,String name) {
		// TODO Auto-generated constructor stub
		super(name);
		this.queue=queue;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		/**
		 * 模拟每个客户端线程可以发送多个请求
		 */
		for(int i=0;i<1;i++){
			/**
			 * 构造请求
			 */
			Request request=new Request(Thread.currentThread().getName());
			/**
			 * 提交请求
			 */
			try {
				queue.put(request);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		/**
		 * 这个方式有一个缺点,即不能获得Server的返回值
		 */
	}
}

(4)Main.java:
public class Main {
	public static void main(String[] args) {
		BlockingQueue<Request> queue=new LinkedBlockingQueue<Request>();
		/**
		 * 启动多个服务端线程
		 */
		for(int i=0;i<30;i++){
			new ServerThread(queue, String.valueOf(i)).start();
		}
		/**
		 * 启动多个客户端线程
		 */
		for(int i=0;i<10;i++){
			new ClientThread(queue, String.valueOf(i)).start();
		}
	}
}

4.2 有返回值给客户端线程

(1)Request.java:
public class Request {
	private String name;
	private Data data;
	public Request(String name) {
		// TODO Auto-generated constructor stub
		this.name=name;
	}
	public  synchronized Data getData() {
		return  data;

	}
	public synchronized void setData(Data data) {
	    this.data=data;
	
	}
}
(2)Data.java:
public class Data {
	private boolean isReady;
	private String content;
	public synchronized void setContent() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		content="finished";
		isReady=true;
		notifyAll();
		
	}
	public synchronized String getContent() {
		while (!isReady) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return content;
	}

}
(3)ServerTask.java:
/**
 * 这里实现了callable接口是为了能够获得返回值
 * @author 深蓝色
 *
 */
public class ServerTask implements Callable<String>{
	/**
	 * 使用阻塞队列,生产者消费者模式
	 */
	private BlockingQueue<Request> queue;
	public ServerTask(BlockingQueue<Request> queue) {
		// TODO Auto-generated constructor stub
		this.queue=queue;
	}
	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		/**
		 * 从队列中获取请求,队列为空则阻塞
		 */
		Request request=queue.take();
		/**
		 * 模拟请求的耗时操作
		 */
		Thread.sleep(1000);
		request.getData().setContent();
		return null;
	}
}
(4)ClientTask.java:
public class ClientTask implements Callable<Data>{
	private BlockingQueue<Request> queue;
	public ClientTask(BlockingQueue<Request> queue) {
		// TODO Auto-generated constructor stub
		this.queue=queue;
	}

	@Override
	public Data call() throws Exception {
		// TODO Auto-generated method stub
		/**
		 * 构造请求,提交请求
		 */
		Request request=new Request(Thread.currentThread().getName());
		request.setData(new Data());
		System.out.println("提交请求");
		queue.put(request);
		/**
		 * 将数据交给服务器端处理
		 * 如果处理完毕,那么getContent直接返回,否则,会阻塞
		 */
		Data data=request.getData();
		System.out.println("获取处理后的结果:"+data.getContent());
		return null;
	}
}
(5)Main.java:
public class Main {
	public static void main(String[] args) throws Exception{
		/**
		 * 公用一个阻塞队列
		 * client向队列中添加请求
		 * Server从队列中取出请求,处理
		 */
		BlockingQueue<Request> queue=new LinkedBlockingQueue<Request>();
		ExecutorService executor=Executors.newCachedThreadPool();
		for(int i=0;i<5;i++){
			executor.submit(new ClientTask(queue));
		}
		for(int i=0;i<5;i++){
			executor.submit(new ServerTask(queue));
		}
	}
}

5 参考文献

1>.Java程序性能优化. 葛一鸣 等著.




你可能感兴趣的:(设计模式,并发,Suspension,Guarded)