线程池异步回掉的简单例子
2017-11-16 22:08
225 查看
本文是一个基于android activity请求网络数据情景,做的一个java的模拟网络异步请求的简单例子,包括了线程池和软引用的简单应用,如果有不对的地方,希望大家可以指正。
1.异步请求是为了执行耗时操作
2.线程池是为了并发多个请求
3.软引用是为了当回掉的类持有的对象被释放的时候,可以被垃圾回收及时处理(当然gc本身并不是即时回收的)
好,下面开始贴代码,然后大概说两句
IntelliJ IDEA 新建工程:AsyncDemo
新建接口:CallBack,代码如下
新建抽象类:CallBackImpl,代码如下
写一个抽象类来实现一个接口的好处是,你可以在抽象类里,做统一的处理,也可以做一个空实现,这样当继承这个抽象类时,就可以不必实现所有接口中定义的方法了,只关注想要的那个回掉的处理就好,而且如果有必须子类做处理的,可以在抽象类中不做实现,这样子类就必须实现这个方法,可以给记性不好的提供方便(O(∩_∩)O)。
新建类:RequestClass,代码如下:
关于这里添加软应用的原因是这样的:
比如说在android的activity中做一个网络请求,我会在这个activity中写一个内部类,这个内部类的好处是,当网络访问成功后,可以在相应的回掉中处理数据的展示,而且可以直接操作activity这个类中的成员。
这样有一个不好的地方,就是这个回掉会持有这个activity的引用,也就是强引用,如果这个activity finish了而异步还没有完成,就会导致activity不会被及时销毁(假设说gc刚好要回收时),这就是那个老说的可能会导致内存泄露的问题。
但是如果这是个软引用的话,gc就会回收这个activity对象。这样即做到了会被及时回收,也做到了直接操作activity类内的成员的做法(当然,如果你不想用软引用,也可以把回掉抽取出去,然后以一个广播的形式通知activity做处理)
下面的main方法也模拟了这个效果。
新建类:DemoClass
可以把这个类当成一个activity,在页面启动后,添加了一个网络请求
新建测试类:MainClass,代码如下
当注释掉 demoClass = null 这句话时,运行结果如下:
当打开 demoClass = null 这句话时,运行结果如下:
就没有了回掉成功的打印,因为显示的调用了一下System.gc();后,这个对象被回收了。但是如果做异步请求时,不加软应用的话,执行结果如下:
修改RequestClass中的代码如下:
运行结果如下:
即使将demoClass置为null,并且调用了 System.gc(); 还是会回掉,回掉成功的方法。因为这是个强引用,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
关于java的四种引用类型可以参考:
https://www.cnblogs.com/mjorcen/p/3968018.html
另外,如果你在一个非UI线程中,想要在回掉中直接处理UI的话,可以这么干,就会切换到主线程,代码如下:
好了,先说这么多。
资源下载地址:http://download.csdn.net/download/u013488064/10122082
1.异步请求是为了执行耗时操作
2.线程池是为了并发多个请求
3.软引用是为了当回掉的类持有的对象被释放的时候,可以被垃圾回收及时处理(当然gc本身并不是即时回收的)
好,下面开始贴代码,然后大概说两句
IntelliJ IDEA 新建工程:AsyncDemo
新建接口:CallBack,代码如下
public interface CallBack { void onFailed(String errorMsg); void onSuccess(String threadName); }
新建抽象类:CallBackImpl,代码如下
public abstract class CallBackImpl implements CallBack { @Override public void onFailed(String errorMsg) { // 错误统一处理 System.out.println(errorMsg); } }
写一个抽象类来实现一个接口的好处是,你可以在抽象类里,做统一的处理,也可以做一个空实现,这样当继承这个抽象类时,就可以不必实现所有接口中定义的方法了,只关注想要的那个回掉的处理就好,而且如果有必须子类做处理的,可以在抽象类中不做实现,这样子类就必须实现这个方法,可以给记性不好的提供方便(O(∩_∩)O)。
新建类:RequestClass,代码如下:
public class RequestClass { // 对回掉做一个软引用 private WeakReference<CallBack> weakRequest; // 创建一个线程池,最多启动6个线程,超过6个线程的会排队等待 private ExecutorService service = Executors.newFixedThreadPool(6); private RequestClass() { } // 登记式/静态内部类,一种单例模式的写法 // 参考:http://www.runoob.com/design-pattern/singleton-pattern.html private static class Singleton { private static final RequestClass INSTANCE = new RequestClass(); } public static RequestClass getInstance() { return Singleton.INSTANCE; } public void request(CallBack callBack, int index) { weakRequest = new WeakReference<>(callBack); service.execute(new Runnable() { @Override public void run() { try { System.out.println("线程: " + index + " 开始...."); Thread.sleep(3000);//模拟耗时 System.out.println("线程: " + index + " 结束...."); // callBack.onSuccess("线程: " + index); if (weakRequest.get() != null) { weakRequest.get().onSuccess("线程: " + index); } } catch (InterruptedException e) { if (weakRequest.get() != null) { weakRequest.get().onFailed("错误信息"); } e.printStackTrace(); } } }); } }
关于这里添加软应用的原因是这样的:
比如说在android的activity中做一个网络请求,我会在这个activity中写一个内部类,这个内部类的好处是,当网络访问成功后,可以在相应的回掉中处理数据的展示,而且可以直接操作activity这个类中的成员。
这样有一个不好的地方,就是这个回掉会持有这个activity的引用,也就是强引用,如果这个activity finish了而异步还没有完成,就会导致activity不会被及时销毁(假设说gc刚好要回收时),这就是那个老说的可能会导致内存泄露的问题。
但是如果这是个软引用的话,gc就会回收这个activity对象。这样即做到了会被及时回收,也做到了直接操作activity类内的成员的做法(当然,如果你不想用软引用,也可以把回掉抽取出去,然后以一个广播的形式通知activity做处理)
下面的main方法也模拟了这个效果。
新建类:DemoClass
public class DemoClass { private Request request; public DemoClass(int index) { request = new Request(); //模拟一个请求 RequestClass.getInstance().request(request, index); } // 实现一个抽象类,处理需要的回掉 class Request extends CallBackImpl { @Override public void onSuccess(String threadName) { System.out.println(threadName + "回掉成功......"); } } }
可以把这个类当成一个activity,在页面启动后,添加了一个网络请求
新建测试类:MainClass,代码如下
public class MainClass { public static void main(String[] args) { // 可以将这个循环数增加,就会看到等待进入线程池的效果 for (int i = 0; i < 5; i++) { DemoClass demoClass = new DemoClass(i); // demoClass = null; System.gc(); } System.out.println("for 循环结束了..."); } }
当注释掉 demoClass = null 这句话时,运行结果如下:
线程: 0 开始.... 线程: 1 开始.... 线程: 2 开始.... 线程: 3 开始.... 线程: 4 开始.... for 循环结束了... 线程: 0 结束.... 线程: 1 结束.... 线程: 0回掉成功...... 线程: 1回掉成功...... 线程: 2 结束.... 线程: 2回掉成功...... 线程: 4 结束.... 线程: 4回掉成功...... 线程: 3 结束.... 线程: 3回掉成功......
当打开 demoClass = null 这句话时,运行结果如下:
线程: 0 开始.... 线程: 2 开始.... 线程: 4 开始.... 线程: 3 开始.... for 循环结束了... 线程: 1 开始.... 线程: 4 结束.... 线程: 1 结束.... 线程: 3 结束.... 线程: 0 结束.... 线程: 2 结束....
就没有了回掉成功的打印,因为显示的调用了一下System.gc();后,这个对象被回收了。但是如果做异步请求时,不加软应用的话,执行结果如下:
修改RequestClass中的代码如下:
public void request(CallBack callBack, int index) { // weakRequest = new WeakReference<>(callBack); service.execute(new Runnable() { @Override public void run() { try { System.out.println("线程: " + index + " 开始...."); Thread.sleep(3000);//模拟耗时 System.out.println("线程: " + index + " 结束...."); callBack.onSuccess("线程: " + index); // if (weakRequest.get() != null) { // weakRequest.get().onSuccess("线程: " + index); // } } catch (InterruptedException e) { // if (weakRequest.get() != null) { // weakRequest.get().onFailed("错误信息"); // } e.printStackTrace(); } } }); }
运行结果如下:
线程: 0 开始.... 线程: 2 开始.... 线程: 1 开始.... 线程: 4 开始.... for 循环结束了... 线程: 3 开始.... 线程: 0 结束.... 线程: 0回掉成功...... 线程: 4 结束.... 线程: 2 结束.... 线程: 2回掉成功...... 线程: 1 结束.... 线程: 1回掉成功...... 线程: 3 结束.... 线程: 3回掉成功...... 线程: 4回掉成功......
即使将demoClass置为null,并且调用了 System.gc(); 还是会回掉,回掉成功的方法。因为这是个强引用,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
关于java的四种引用类型可以参考:
https://www.cnblogs.com/mjorcen/p/3968018.html
另外,如果你在一个非UI线程中,想要在回掉中直接处理UI的话,可以这么干,就会切换到主线程,代码如下:
Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { //切换到主线程 } });
好了,先说这么多。
资源下载地址:http://download.csdn.net/download/u013488064/10122082
相关文章推荐
- 异步请求数据简单例子
- 简单异步和反射小例子
- 线程池简单例子
- 线程和线程池的理解与java简单例子
- spring+ActiveMQ+JMS+线程池实现简单的分布式,多线程,多任务的异步任务处理系统
- 异步TCP---简单聊天例子
- AsyncTask异步任务简单例子
- linux下异步IO的简单例子【转】
- 扩展线程池ThreadPoolExecutor的简单例子
- 一个简单的ajax实例:异步请求的例子
- 求C#关于线程池的简单例子
- 使用Guava的eventbus完成异步事件的简单例子
- 异步TCP---简单聊天例子
- 使用$.get()从数据库异步请求数据的简单例子
- Boost.asio实现的同步、异步TCP通信的简单例子
- AJAX异步提交的简单例子
- C#简单异步例子
- java线程池最简单例子
- java线程及操作实例,线程池简单例子
- Extjs中加载异步树的最简单例子实现