Android 并发二三事之利用CountDownLatch 或 ConditionVariable实现自定义Future
来源:互联网 发布:网络诋毁公司如何处理 编辑:程序博客网 时间:2024/05/01 23:19
前言:
Android 并发第三篇
介绍如何利用 CountDownLatch 或 ConditionVariable 实现自定义Future,用于适应项目中的需求。
即阻塞当前线程,等待其他线程的结果返回,其功能类似于FutureTask。
首先介绍 CountDownLatch(共享锁 Java)以及 ConditionVariable(Android)。
一、CountDownLatch
1、CountDownLatch 简介:
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。
CountDownLatch是通过“共享锁”实现的。在创建CountDownLatch中时,会传递一个int类型参数count,该参数是“锁计数器”的初始状态,表示该“共享锁”最多能被count个线程同时获取。当某线程调用该CountDownLatch对象的await()方法时,该线程会等待“共享锁”可用时,才能获取“共享锁”进而继续运行。而“共享锁”可用的条件,就是“锁计数器”的值为0!而“锁计数器”的初始值为count,每当一个线程调用该CountDownLatch对象的countDown()方法时,才将“锁计数器”-1;通过这种方式,必须有count个线程调用countDown()之后,“锁计数器”才为0,而前面提到的等待线程才能继续运行!
CountDownLatch 本身是基于AQS实现的,具体其原理,这里不做太多介绍。
2、方法简介:
CountDownLatch(int count)
构造一个用给定计数初始化的 CountDownLatch。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
boolean await(long timeout, TimeUnit unit)
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
void countDown()
// 返回当前计数。
long getCount()
3、使用示例:
private void executeAfterWorker() { try { Log.d(TAG, "execute....................."); CountDownLatch countDownLatch = new CountDownLatch(2); Worker worker1 = new Worker(countDownLatch); Worker worker2 = new Worker(countDownLatch); worker1.start(); worker2.start(); Log.d(TAG, "execute wait"); //等待其他的线程执行完。 countDownLatch.await(); //其他线程执行完后,在执行其他的操作 Log.d(TAG, "execute finish......"); } catch (Exception e) { } } private static class Worker extends Thread { private CountDownLatch countDownLatch; public Worker(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @Override public void run() { try { Thread.sleep(100); Log.d(TAG, Thread.currentThread().getId() + " run"); } catch (Exception e) { } finally { //调用countDown()计数器减一 countDownLatch.countDown(); } } }
4、结果:
D/Demo: execute..................... D/Demo: execute wait D/Demo: 16090 run D/Demo: 16091 run D/Demo: execute finish......
5、利用CountDownLatch 自定义Future :
功能介绍:在子线程中开启其他线程联网请求数据,
阻塞当前线程,等待结果返回,或者超时。
//请求数据private void request() { new Thread(new Runnable() { @Override public void run() { try{ ResultFuture future = new ResultFuture(1); request(future); com.loader.demo.ResponInfo responInfo= future.get(); Log.d(TAG, responInfo.getName() + "requestAd"); }catch (Exception e){ } } }).start(); } /** * 模拟联网等耗时操作 * @param resultListener */ private void request(final ResultListener resultListener) { new Thread(new Runnable() { @Override public void run() { try{ Thread.sleep(3000); }catch (Exception e){ } //模拟成功后回调 resultListener.onSuccess(new com.loader.demo.ResponInfo("BMW", 2000)); } }).start(); }
//数据实体 public class ResponInfo { private String name; private long price; public ResponInfo(String name, long price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getPrice() { return price; } public void setPrice(long price) { this.price = price; } }
/** * 自定义Future。 * 实现Future接口,提供get() 相关方法。 * 实现ResultListener 接口,获取成功或失败的回调信息。 * */public class ResultFuture implements Future<ResponInfo>, ResultListener{ private CountDownLatch mCountDownLatch; private ResponInfo mResponInfo; private boolean mResult = false; public ResultFuture(int count) { //开启count 个线程,等待 count 个线程执行完或超时,才会返回结果。 mCountDownLatch = new CountDownLatch(count); } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return false; } @Override public ResponInfo get() throws InterruptedException, ExecutionException { try { return doGet(null); }catch (Exception e){ return null; } } @Override public ResponInfo get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit)); } private ResponInfo doGet(Long time) throws InterruptedException, ExecutionException, TimeoutException{ //如果已经有结果,在直接返回 if(mResult) { return mResponInfo; } //阻塞当前线程,直到调用mCountDownLatch.countDown();或者超时。 if(time == null) { mCountDownLatch.await(); }else {//加入超时时间 mCountDownLatch.await(time, TimeUnit.MILLISECONDS); } if(!mResult) { //超时抛出异常 throw new TimeoutException(); } return mResponInfo; } @Override public void onSuccess(ResponInfo responInfo) { //成功,将结果赋值给mResponInfo,调用countDown()方法,计数器减一 this.mResponInfo = responInfo; mResult = true; mCountDownLatch.countDown(); } @Override public void onFail() { //失败,计数器减一 mCountDownLatch.countDown(); }}
/** * 联网结果回调接口 */public interface ResultListener { void onSuccess(ResponInfo responInfo); void onFail();}
二、ConditionVariable:
1、ConditionVariable 简介:
ConditionVariable类位于android.os.ConditionVariable,它可以帮助Android线程同步。
其内部的实现的就是调用了wait()以及notifyAll();
之前介绍的 CountDownLatch 是Java 的类。而 ConditionVariable 是Android特有的。CountDownLatch 是共享锁,
当前线程阻塞,要等待其他的线程都执行完,也就是计数器等于0时,才会向下执行。
而ConditionVariable 是Android 对 wait() , notifyAll()的封装,调用block()方法阻塞当前线程,等待被唤醒。
2、构造方法:
public ConditionVariable() { mCondition = false; } public ConditionVariable(boolean state) { mCondition = state; }
默认mCondition 即为false。一般会用无参的构造方法。
3、方法介绍:
ConditionVariable为我们提供以下几个方法:
//释放所有被阻塞的线程,任何线程在调用open()后调用block()都不会生效,除非先调用了close() ,后调用block()。
public void open()
//将条件(condition)重置为关闭状态
public void close()
//阻塞当前线程,直到条件(condition)被打开。如果条件(condition)本来是打开的,将不会生效,会立即返回。
public void block()
//阻塞当前线程,直到条件(condition)被打开,或者超时。如果条件(condition)本来是打开的,将不会生效,会立即返回。
public boolean block(long timeout)
4、使用实例:
private void executeAfterWorker() { try { Log.d(TAG, "execute....................."); ConditionVariable conditionVariable = new ConditionVariable(); Worker worker = new Worker(conditionVariable); worker.start(); Log.d(TAG, "execute wait"); conditionVariable.block(); Log.d(TAG, "execute finish......"); } catch (Exception e) { } } private static class Worker extends Thread { private ConditionVariable conditionVariable; public Worker(ConditionVariable conditionVariable) { this.conditionVariable = conditionVariable; } @Override public void run() { try { Thread.sleep(100); Log.d(TAG, Thread.currentThread().getId() + " run"); } catch (Exception e) { } finally { conditionVariable.open(); } } }
5、结果:
D/Demo: execute..................... D/Demo: execute wait D/Demo: 16094 run D/Demo: execute finish......
6、下面来看如何利用ConditionVariable 打造自定义的Future。
在这里就给出Future 的实现类,其他的代码和 CountDownLatch 的都一样。
public class ResultFuture implements Future<ResponInfo>, ResultListener { private ResponInfo mResponInfo; private boolean mResult = false; private ConditionVariable conditionVariable; public ResultFuture() { conditionVariable = new ConditionVariable(); } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return false; } @Override public ResponInfo get() throws InterruptedException, ExecutionException { try { return doGet(null); }catch (Exception e){ return null; } } @Override public ResponInfo get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit)); } private ResponInfo doGet(Long time) throws InterruptedException, ExecutionException, TimeoutException{ //如果已经有结果,在直接返回 if(mResult) { return mResponInfo; } if(time == null) { conditionVariable.block(); }else {//加入超时时间 conditionVariable.block(time); } if(!mResult) { //超时抛出异常 throw new TimeoutException(); } return mResponInfo; } @Override public void onSuccess(ResponInfo responInfo) { this.mResponInfo = responInfo; mResult = true; conditionVariable.open(); } @Override public void onFail() { conditionVariable.open(); }}
OK, 利用 CountDownLatch 或 ConditionVariable 实现自定义的Future,就介绍到这里。其实原理非常的简单。就是需要当前的线程等待结果。
或者超时。
之所以介绍 CountDownLatch 和 ConditionVariable 是因为这两个比较熟悉。哈哈。在项目中都用到过多次。其中利用ConditionVariable 写过
和Volley想结合的代码。就是编写一个类实现Future,也同时实现Volley 访问网络成功和失败的结果。利用ConditionVariable 实现阻塞,等待结果。
感觉用起来非常的舒服。当然在 ResultFuture 编写的还相对简单,在其中我们还可以完善 isDone() 等方法。
下一篇开始将会介绍Android方面用于多线程方面的类,第一个是 AsyncTask , AsyncTask 的用法以及原理有太多人介绍过了,但这里我还是会介绍
其用法,原理,并尝试从不同的角度去分析,理解。
注: 文中如有有错误的,需要提高的代码,请您留言,我会及时改正。
- Android 并发二三事之利用CountDownLatch 或 ConditionVariable实现自定义Future
- Android并发二三事之Callable,Future,FutureTask
- Android并发二三事之Callable,Future,FutureTask
- android ConditionVariable
- Android ConditionVariable
- Java并发之CountDownLatch
- Java并发之CountDownLatch
- 并发库之CountDownLatch
- 并发编程之CountDownLatch
- 并发编程实现模型之(一)Future模式
- CountDownLatch实现并发多线程操作
- Android并发编程之白话文详解Future,FutureTask和Callable
- Android并发编程之白话文详解Future,FutureTask和Callable
- Android并发编程之白话文详解Future,FutureTask和Callable
- Android并发编程之白话文详解Future,FutureTask和Callable
- Android并发编程之详解Future,FutureTask和Callable
- Java 并发编程之 CountDownLatch
- java并发编程之CountDownLatch
- 中国商圈数据,中国行政区数据,省,市,区县,商圈【全国地域数据】【Json格式】
- MSSQL第二篇:非AD环境搭建AlwaysOn
- 第11周项目1-验证算法(2)二叉树构造算法的验证
- 数据库编程
- 实验 将内容存储在内存卡中
- Android 并发二三事之利用CountDownLatch 或 ConditionVariable实现自定义Future
- Java String对象的经典问题(new String())
- web前端开发中防治重复提交
- Linux常见命令问答
- eclipse快捷键用法
- 时间、日期的常识
- 使用npm安装一些包失败了的看过来(npm国内镜像介绍),亲测可用,非常吊!
- 【FontsManager】安卓一行代码实现自定义字体替换
- 第一次程序慢