线程池异步回掉的简单例子
来源:互联网 发布:tm域名有必要注册吗 编辑:程序博客网 时间:2024/06/18 16:23
本文是一个基于android activity请求网络数据情景,做的一个java的模拟网络异步请求的简单例子,包括了线程池和软引用的简单应用,如果有不对的地方,希望大家可以指正。
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
没C币了,要了2个C币 ^_^
- 线程池异步回掉的简单例子
- 线程的简单例子
- 线程池简单例子
- 扩展线程池ThreadPoolExecutor的简单例子
- POSIX线程的简单例子
- 简单的线程聊天例子
- 一个简单的线程例子
- java 线程的简单例子
- 一个简单的线程例子
- AJAX异步提交的简单例子
- linux下异步IO的简单例子
- linux下异步IO的简单例子
- java线程池简单例子
- 简单理解异步、线程池和队列的作用
- 线程简单通信 线程回调 例子
- 异步简单例子
- C#简单异步例子
- 求C#关于线程池的简单例子
- polya 定理总结
- SpringCloud教程第一篇:服务的注册与发现(Eureka)
- 剑指Offer 面试题18:删除链表节点 Java代码实现
- Hibernate快速入门案例——手动修改和删除记录
- 第一个小小程序
- 线程池异步回掉的简单例子
- CocosCreator
- C语言中常用const声明常量有什么好处呢?(get了吗?)
- NOIP2008提高组
- 2017开学训练第十二周周中总结
- java基础8:properties集合,序列化,打印流,commons-IO,对应案例
- Canvas和svg的区别
- 信息熵是什么
- 02-设置文件类型的扩展名显示