感谢看了这篇书 我才终于懂了异步消息的概念
异步
本节和下一节线程池进行异步 是 异步的两大主要形式
-
现实场景:主任
委托
员工A去打印 委托员工B去买水 主任不关心他们返回的结果
主任就接着做自己的事情了 -
该模式又成为多线程下的代理模式 多线程下的适配器模式
该模式需要以下几个角色:
- 客户访问类
- 代理类 Host 在客户端只创建一个host实例
- 被代理类 Helper
class Client{
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"调用主线程");
Host h=new Host();
h.request("mysql");
h.request("mq");
System.out.println(Thread.currentThread().getName()+"调用主线程结束");
}
}
public class Host {
private final Helper helper=new Helper();
public void request(String s){
System.out.println(Thread.currentThread().getName()+"调用request");
new Thread(new Runnable() {
@Override
public void run() {
helper.handle(s);
}
}).start();
System.out.println(Thread.currentThread().getName()+"调用request结束");
}
}
public class Helper {
public void handle(String s){
try {
System.out.println(Thread.currentThread().getName()+"调用handler处理"+s);
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"调用handler结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在host类中 新启线程去调用helper中的handle
不论handle方法执行多久 客户端永远很快获得host方法Request响应
handle中的sleep时间加长 客户端需要等待更久的时间么?
主线程顺序调用客户端请求的request方法
request方法里让helper帮忙做这件事 帮忙做那件事 吩咐完这些命令 委托完这些功能 主线程就可以终止了
request方法里新启动的线程 消耗多久的时间都不会影响request的响应性 他不等待handler方法结束 而是立即结束并响应 之后那些helper会自行做工作
每次调用request都会创建一个helper新实例?
nope
现实场景1:服务器
面对众多的请求 只有一个服务器 Host
服务器为每一个请求都新建一个线程
- 尤其现在的请求涉及大量的IO操作 输入输出 或者长时间的业务逻辑
我们在服务器中正常响应客户端(比如说显示操作成功 )
但是具体的业务给其他线程跑 保证了服务器的响应速度
下面是一个非常简单的demo
public class WebServer {
private final MyService service = new MyService();
private int port;
public WebServer(int port) {
this.port = port;
}
public void execute() throws IOException {
ServerSocket serverSocke = new ServerSocket(port);
try {
while (true) {
final Socket client = serverSocke.accept();
service.service(client);
}
} finally {
serverSocke.close();
}
}
}
class MyService {
public void service(final Socket clientSocket) {
new Thread(new Runnable() {
@Override
public void run() {
try {
doService(clientSocket);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public void doService(Socket clientSocket) throws InterruptedException {
}
}
现实场景2:多次刷新请求 如何处理
上面的小demo 没有做service那边多线程的处理
如果频繁的刷新网页
- 是否只让一个请求好使 就不用管之后刷新的请求了
模拟有一个按钮 我们点击一次就控制台打印 就模拟请求服务器一样
我们多次点击 模拟多次刷新看会出现什么问题
public class Button {
final ButtonService service = new ButtonService();
public void request() {
new Thread(new Runnable() {
@Override
public void run() {
try {
service.doService();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public static void main(String[] args) {
Button button = new Button();
button.request();
button.request();
}
}
class ButtonService {
public void doService() throws InterruptedException {
System.out.print(Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.print(i);
}
System.out.println("done!");
}
}
混合输出 交替打印
而且点击两次 其实不用请求两次 一次就可以
按序打印 但是还是请求了两次 没必要
class ButtonService {
private static volatile boolean workAlready=false;
public synchronized void doService() throws InterruptedException {
if(workAlready){
System.out.println(Thread.currentThread().getName()+"被阻塞");
return ;
}
System.out.print(Thread.currentThread().getName());
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.print(i);
}
System.out.println("done!");
workAlready=true;
}
}