在正常的业务中使用同步线程,如果服务器每处理一个请求,就创建一个线程的话,会对服务器的资源造成浪费。因为这些线程可能会浪费时间在等待网络传输,等待数据库连接等其他事情上,真正处理业务逻辑的时间很短很短,但是其他线程在线程池满了之后又会阻塞,等待前面的线程处理完成。而且,会出现一个奇怪的现象,客户端的请求被阻塞,但是cpu的资源使用却很低,大部分线程都浪费在处理其他事情上了。所以,这就导致服务器并发量不高。
而异步,则可以解决这个问题。
我们可以把需要用到cpu的业务处理使用异步来实现,这样其他请求就不会被阻塞,而且cpu会保持比较高的使用率。
今天就学习了使用回调来实现异步的方法。我们设想一个情景,A是处理业务的一个步骤,A需要解决一个问题,这时候A可以问B,让B来告诉A答案,这期间,A可以继续做自己的事情,而不用因为B做的事而阻塞。于是,我们想到给B设置一个线程,让B去处理耗时的操作,然后处理完之后把结果告诉A。所以这个问题的要点就在于B处理完之后如何把结果告诉A。我们可以直接在A中写一个方法对B处理完的结果进行处理,然后B处理完之后调用A这个方法。这样A调用B去处理过程,B调用A的C方法去处理结果就叫做回调。
1 package CallBack; 2 3 public interface CallBack { 4 /* 5 *A处理结果的方法,为什么要写这个接口呢? 6 *因为可能不止A需要用到B的处理过程,如果很多地方需要用到B 7 * 那么传入B的方法就不可能只传A类,所以要定义一个接口, 8 * 传入B的处理方法的参数就是这个接口对象 9 * */ 10 public void solve(String result); 11 }
1 package CallBack; 2 3 public class A implements CallBack { 4 private B b; 5 6 public A(B b){ 7 this.b=b; 8 } 9 10 //A需要解决一个问题,所以他把问题交给B处理,B单独创建一个线程,不影响A的运行 11 public void ask(final String question){ 12 System.out.println("A问了B一个问题"); 13 new Thread(()->{ 14 //B想要帮A处理东西,就必须知道谁让自己处理的,所以要传入a,也要知道a想处理什么,所以要传入question 15 b.executeMessage(A.this,question); 16 }).start(); 17 //A把要处理的事情交给b之后,就可以自己去玩耍了,或者去处理其他事情 18 play(); 19 } 20 21 public void play(){ 22 System.out.println("我要逛街去了"); 23 } 24 25 //A拿到了B处理完成的结果,可以进行一些操作,比如把结果输出 26 @Override 27 public void solve(String result) { 28 System.out.println("B告诉A的答案是--》"+result); 29 } 30 31 }
1 package CallBack; 2 3 public class B { 4 public void executeMessage(CallBack callBack,String question){ 5 System.out.println(callBack.getClass()+"问的问题--》"+question); 6 try { 7 Thread.sleep(3000); 8 } catch (InterruptedException e) { 9 e.printStackTrace(); 10 } 11 String result="答案是2"; 12 callBack.solve(result); 13 } 14 }
1 package CallBack; 2 3 public class test { 4 public static void main(String[] args) { 5 B b=new B(); 6 A a=new A(b); 7 a.ask("1+1=?"); 8 } 9 }
运行结果: A问了B一个问题 我要逛街去了 class CallBack.A问的问题--》1+1=? B告诉A的答案是--》答案是2 Process finished with exit code 0