现实问题
特殊的刷新界面需求如下:
- 请求后台,返回数据中包含若干个链接link0、link1···
- 访问各个link等待结果
- 如果时间超过400ms或者各个link都请求成功,那么才刷新当前界面
总结一下就是,要么等400ms,要么各个请求都成功了,才去刷新界面。
何解
这个需求发生在客户端,要写一个特殊的加载器的逻辑。
经过查阅,我发现Java各种获取线程执行结果的API都是线程阻塞的,比如FutureTask(也可能我没找到···)
再比如CountDownLatch,在等待各个线程执行结束和超时的时候,当前线程也是阻塞的。
-
自己写一个线程池,一个计数器,回调
每个任务开启子线程,然后成功回调到主线程,有一个计数器在计算完成任务数
同时,在执行子线程任务时,主线程执行一个延时400ms的任务(runnable),如果任务先结束就取消掉这个400ms任务,否则执行400ms任务。
这里有个状态问题,就是只能有一个被执行,要么是全完成,要么是400ms的任务,所以还需要一个状态值控制这两个互斥。伪代码:
mTimer = new Runnable() { @Override public void run() { if (!mHasRefreshed) { //刷新 } } }; mThreadPool.execute(task); mHandler.postDelayed(mTimer, 400); taskManager.bindCallback(new Callback(){ @Override public void onTaskSuccess() { counter++; if (!mHasRefreshed&&counter==tasks.size()) { //刷新 } }); 大专栏 任务模型 - 北邙山之光的博客">//task中,每个任务成功 Handler mTaskHandler = new Handler(Looper.getMainLooper()); mTaskHandler.post(new Runnable(){ @Override public void run() { if (!mHasRefreshed) { callback.onTaskSuccess(); } } });
大致思路如此,不必纠结细节
-
用封装好的Java API
比如CountDownLatch
CountDownLatch countDownLatch = new CountDownLatch(tasks.size()); for(int i = 0; i < tasks.size(); i++){ mThreadPool.execute(tasks.get(i)); } countDownLatch.await(200,TimeUnit.MILLISECONDS); //task中 countDownLatch.countDown();
但是会阻塞线程哦,所以要放到子线程,然后回调到主线程
不知道最优方案是啥
不知道后台工程师,在后台遇到类似逻辑怎么写,这种获取线程执行结果的,都是阻塞线程的,但是在客户端,主线程是不可被阻塞的。