目录
多线程编程对比: iOS与Android
android的多线程编程有
- Thread 
- Handler 
- AsyncTask 
- IntentService 
android多线程详细可以参考android学习 之 Service
iOS的多线程编程有
- NSthread 
- GCD 
- NSOperationQueue 
iOS多线程详细可以参考Objective-C学习 之 GCD / iOS最佳实践 之 优先使用NSOperationQueue而不是GCD / iOS开发 之 Queue和Thread
对比两个平台的多线程编程, android还是稍逊一些
- Handler和IntentService的多线程编程, 开销有些大, 而GCD配合Block, 简洁好用并且功能也很强大 
- AsyncTask处理消息队列和多线程同步, 是比较费劲的, 而NSOperationQueue, 仍然是简单好用五颗星 
那有没有一种方案可以让android变得和iOS一样简单好用呢?
答案就是今天的主角BoltsFramework/Bolts-Android
Bolts-Android
Bolts-Android由Parse"荣誉"出品, 为什么说是"荣誉"呢?
因为作为Baas的鼻祖, Parse已经成功地死在了沙滩上, 但是被Facebook关门之后, 它仍然发挥了余热, Parse的很多项目都在Github Parse上开源了
废话不多说, 直接看例子吧
Tasks
想要在当前线程执行Task, 就是这么简单
Task.call(new Callable<Boolean>() {    @Override
    public Boolean call() throws Exception {
        XLog.d(Thread.currentThread().getName() + " " + "call in current thread");        return true;
    }
});如果想在后台线程执行Task
Task.callInBackground(new Callable<Boolean>() {    @Override
    public Boolean call() throws Exception {
        XLog.d(Thread.currentThread().getName() + " " + "call in background thread");        return true;
    }
});如果想在UI主线程执行Task
Task.call(new Callable<Boolean>() {    @Override
    public Boolean call() throws Exception {
        XLog.d(Thread.currentThread().getName() + " " + "call in main thread");        return true;
    }
}, Task.UI_THREAD_EXECUTOR);如果想要延时执行Task
Task.delay(2000).continueWith(new Continuation<Void, Void>() {    @Override
    public Void then(Task<Void> task) throws Exception {
        XLog.d(Thread.currentThread().getName() + " " + "call in main thread (after delay 2 seconds)");        return null;
    }
});是不是简单到让人无法相信? 其实这里的Task和iOS中的GCD编程是类似的(详细可以参考Objective-C学习 之 GCD)
Chaining Tasks
热完身, 我们来看下Bolts-Android的函数式编程(关于函数式编程详细可以参考谈谈函数式响应式编程(Functional Reactive Programming))
Task.call(new Callable<Boolean>() {    @Override
    public Boolean call() throws Exception {
        XLog.d(Thread.currentThread().getName() + " calling");        return true;
    }
}, Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Boolean, String>() {    @Override
    public String then(Task<Boolean> task) throws Exception {
        Thread.sleep(2000);
        XLog.d(Thread.currentThread().getName() + " onSuccess " + task.getResult());        return "hello bolts";
    }
}, Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<String, Void>() {    @Override
    public Void then(Task<String> task) throws Exception {
        XLog.d(Thread.currentThread().getName() + " continueWith " + task.getResult());        return null;
    }
}, Task.UI_THREAD_EXECUTOR);打印结果如下
main calling pool-2-thread-1 onSuccess truemain continueWith hello bolts
通过函数式的链式编程, 轻松地实现了Task的同步和多线程的切换(怎么忽然就想到了RxJava了呢? 看来下期可以来个Bolts-Android大战RxJava的专题)
Group Tasks
Group Task是我取得名字哈, 所谓Group Tasks, 就是指多个Task组成的一组Tasks
Task.call(new Callable<Boolean>() {    @Override
    public Boolean call() throws Exception {
        XLog.d(Thread.currentThread().getName() + " calling");        return true;
    }
}, Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Boolean, List<Task<Void>>>() {    @Override
    public List<Task<Void>> then(Task<Boolean> task) throws Exception {
        XLog.d(Thread.currentThread().getName() + " tasks start");
        List<Task<Void>> tasks = new ArrayList<Task<Void>>();
        tasks.add(asyncOperation1());
        tasks.add(asyncOperation2());
        Task.whenAll(tasks).waitForCompletion();
        XLog.d(Thread.currentThread().getName() + " tasks end");        return tasks;
    }
}, Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<List<Task<Void>>, Void>() {    @Override
    public Void then(Task<List<Task<Void>>> task) throws Exception {
        XLog.d(Thread.currentThread().getName() + " done");        return null;
    }
}, Task.UI_THREAD_EXECUTOR);其中asyncOperation1和asyncOperation2的定义如下
private Task<Void> asyncOperation1() {    return Task.callInBackground(new Callable<Void>() {        @Override
        public Void call() throws Exception {
            XLog.i("asyncOperation1 start");            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                XLog.e(e.getMessage());
            }
            XLog.i("asyncOperation1 end");            return null;
        }
    });
}private Task<Void> asyncOperation2() {    return Task.callInBackground(new Callable<Void>() {        @Override
        public Void call() throws Exception {
            XLog.i("asyncOperation2 start");            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                XLog.e(e.getMessage());
            }
            XLog.i("asyncOperation2 end");            return null;
        }
    });
}后面的continueWith会等asyncOperation1和asyncOperation2都执行完成后再执行
打印结果如下
main calling pool-2-thread-1 tasks start asyncOperation1 start asyncOperation2 start asyncOperation1 end asyncOperation2 end pool-2-thread-1 tasks end main done
有没有小试牛刀的感觉? 我们接着来看下面的用法
Tasks in Parallel
final Executor PARALLEL_EXECUTOR = Executors.newCachedThreadPool();
Task.call(new Callable<Void>() {    @Override
    public Void call() throws Exception {        for (int i = 0; i < 100; i++) {            if (i % 2 == 0) {
                XLog.i(Thread.currentThread().getName() + " i = " + i);
            }
        }        return null;
    }
}, PARALLEL_EXECUTOR);
Task.call(new Callable<Void>() {    @Override
    public Void call() throws Exception {        for (int i = 0; i < 100; i++) {            if (i % 2 == 1) {
                XLog.i(Thread.currentThread().getName() + " i = " + i);
            }
        }        return null;
    }
}, PARALLEL_EXECUTOR);打印结果如下
pool-2-thread-1 i = 0 pool-2-thread-2 i = 50 pool-2-thread-1 i = 1 pool-2-thread-2 i = 51 pool-2-thread-1 i = 2 pool-2-thread-2 i = 52 pool-2-thread-1 i = 3 pool-2-thread-2 i = 53 pool-2-thread-1 i = 4 pool-2-thread-2 i = 54 pool-2-thread-1 i = 5 pool-2-thread-1 i = 6 pool-2-thread-2 i = 55 pool-2-thread-2 i = 56 pool-2-thread-1 i = 7 pool-2-thread-1 i = 8 pool-2-thread-2 i = 57 pool-2-thread-2 i = 58 pool-2-thread-1 i = 9 pool-2-thread-2 i = 59 pool-2-thread-1 i = 10 pool-2-thread-2 i = 60 pool-2-thread-1 i = 11 pool-2-thread-2 i = 61 pool-2-thread-1 i = 12 pool-2-thread-2 i = 62 pool-2-thread-1 i = 13 pool-2-thread-2 i = 63 pool-2-thread-1 i = 14 pool-2-thread-2 i = 64 pool-2-thread-1 i = 15 pool-2-thread-2 i = 65 pool-2-thread-1 i = 16 pool-2-thread-2 i = 66 pool-2-thread-1 i = 17 pool-2-thread-2 i = 67 pool-2-thread-1 i = 18 pool-2-thread-1 i = 19 pool-2-thread-2 i = 68 pool-2-thread-1 i = 20 pool-2-thread-2 i = 69 pool-2-thread-1 i = 21 pool-2-thread-2 i = 70 pool-2-thread-1 i = 22 pool-2-thread-2 i = 71 pool-2-thread-1 i = 23 pool-2-thread-2 i = 72 pool-2-thread-1 i = 24 pool-2-thread-2 i = 73 pool-2-thread-2 i = 74 pool-2-thread-1 i = 25 pool-2-thread-2 i = 75 pool-2-thread-1 i = 26 pool-2-thread-2 i = 76 pool-2-thread-1 i = 27 pool-2-thread-2 i = 77 pool-2-thread-1 i = 28 pool-2-thread-2 i = 78 pool-2-thread-1 i = 29 pool-2-thread-2 i = 79 pool-2-thread-1 i = 30 pool-2-thread-1 i = 31 pool-2-thread-2 i = 80 pool-2-thread-1 i = 32 pool-2-thread-2 i = 81 pool-2-thread-1 i = 33 pool-2-thread-2 i = 82 pool-2-thread-1 i = 34 pool-2-thread-2 i = 83 pool-2-thread-2 i = 84 pool-2-thread-1 i = 35 pool-2-thread-2 i = 85 pool-2-thread-1 i = 36 pool-2-thread-2 i = 86 pool-2-thread-1 i = 37 pool-2-thread-2 i = 87 pool-2-thread-1 i = 38 pool-2-thread-1 i = 39 pool-2-thread-2 i = 88 pool-2-thread-1 i = 40 pool-2-thread-2 i = 89 pool-2-thread-1 i = 41 pool-2-thread-2 i = 90 pool-2-thread-1 i = 42 pool-2-thread-2 i = 91 pool-2-thread-1 i = 43 pool-2-thread-2 i = 92 pool-2-thread-1 i = 44 pool-2-thread-2 i = 93 pool-2-thread-1 i = 45 pool-2-thread-2 i = 94 pool-2-thread-1 i = 46 pool-2-thread-2 i = 95 pool-2-thread-1 i = 47 pool-2-thread-2 i = 96 pool-2-thread-1 i = 48 pool-2-thread-2 i = 97 pool-2-thread-1 i = 49 pool-2-thread-2 i = 98 pool-2-thread-2 i = 99
打印结果有两个发现
- 线程池有两个线程: pool-2-thread-1和pool-2-thread-2 
- 线程池里的线程是并行执行的: 数字都是 
Tasks in Serial
那有没有方法可以让线程池中只有一个线程, 所有Tasks按照queue的方式FIFO依次执行呢? 办法如下
final Executor SERIAL_EXECUTOR = Executors.newSingleThreadExecutor();
Task.call(new Callable<Void>() {    @Override
    public Void call() throws Exception {        for (int i = 0; i < 50; i++) {
            XLog.i(Thread.currentThread().getName() + " i = " + i);
        }        return null;
    }
}, SERIAL_EXECUTOR);
call(new Callable<Void>() {    @Override
    public Void call() throws Exception {        for (int i = 50; i < 100; i++) {
            XLog.i(Thread.currentThread().getName() + " i = " + i);
        }        return null;
    }
}, SERIAL_EXECUTOR);打印结果如下
pool-2-thread-1 i = 0 pool-2-thread-1 i = 1 pool-2-thread-1 i = 2 pool-2-thread-1 i = 3 pool-2-thread-1 i = 4 pool-2-thread-1 i = 5 pool-2-thread-1 i = 6 pool-2-thread-1 i = 7 pool-2-thread-1 i = 8 pool-2-thread-1 i = 9 pool-2-thread-1 i = 10 pool-2-thread-1 i = 11 pool-2-thread-1 i = 12 pool-2-thread-1 i = 13 pool-2-thread-1 i = 14 pool-2-thread-1 i = 15 pool-2-thread-1 i = 16 pool-2-thread-1 i = 17 pool-2-thread-1 i = 18 pool-2-thread-1 i = 19 pool-2-thread-1 i = 20 pool-2-thread-1 i = 21 pool-2-thread-1 i = 22 pool-2-thread-1 i = 23 pool-2-thread-1 i = 24 pool-2-thread-1 i = 25 pool-2-thread-1 i = 26 pool-2-thread-1 i = 27 pool-2-thread-1 i = 28 pool-2-thread-1 i = 29 pool-2-thread-1 i = 30 pool-2-thread-1 i = 31 pool-2-thread-1 i = 32 pool-2-thread-1 i = 33 pool-2-thread-1 i = 34 pool-2-thread-1 i = 35 pool-2-thread-1 i = 36 pool-2-thread-1 i = 37 pool-2-thread-1 i = 38 pool-2-thread-1 i = 39 pool-2-thread-1 i = 40 pool-2-thread-1 i = 41 pool-2-thread-1 i = 42 pool-2-thread-1 i = 43 pool-2-thread-1 i = 44 pool-2-thread-1 i = 45 pool-2-thread-1 i = 46 pool-2-thread-1 i = 47 pool-2-thread-1 i = 48 pool-2-thread-1 i = 49 pool-2-thread-1 i = 50 pool-2-thread-1 i = 51 pool-2-thread-1 i = 52 pool-2-thread-1 i = 53 pool-2-thread-1 i = 54 pool-2-thread-1 i = 55 pool-2-thread-1 i = 56 pool-2-thread-1 i = 57 pool-2-thread-1 i = 58 pool-2-thread-1 i = 59 pool-2-thread-1 i = 60 pool-2-thread-1 i = 61 pool-2-thread-1 i = 62 pool-2-thread-1 i = 63 pool-2-thread-1 i = 64 pool-2-thread-1 i = 65 pool-2-thread-1 i = 66 pool-2-thread-1 i = 67 pool-2-thread-1 i = 68 pool-2-thread-1 i = 69 pool-2-thread-1 i = 70 pool-2-thread-1 i = 71 pool-2-thread-1 i = 72 pool-2-thread-1 i = 73 pool-2-thread-1 i = 74 pool-2-thread-1 i = 75 pool-2-thread-1 i = 76 pool-2-thread-1 i = 77 pool-2-thread-1 i = 78 pool-2-thread-1 i = 79 pool-2-thread-1 i = 80 pool-2-thread-1 i = 81 pool-2-thread-1 i = 82 pool-2-thread-1 i = 83 pool-2-thread-1 i = 84 pool-2-thread-1 i = 85 pool-2-thread-1 i = 86 pool-2-thread-1 i = 87 pool-2-thread-1 i = 88 pool-2-thread-1 i = 89 pool-2-thread-1 i = 90 pool-2-thread-1 i = 91 pool-2-thread-1 i = 92 pool-2-thread-1 i = 93 pool-2-thread-1 i = 94 pool-2-thread-1 i = 95 pool-2-thread-1 i = 96 pool-2-thread-1 i = 97 pool-2-thread-1 i = 98 pool-2-thread-1 i = 99
Error Handling
看完上面的内容, 想必各位从此都是android多线程的"砖家"了吧, 不过请稍等片刻, 还有一个重要的问题没有解释
Task.call(new Callable<String>() {    @Override
    public String call() throws Exception {
        Thread.sleep(2000);        if (1 < 10) {
            XLog.d(Thread.currentThread().getName() + " RuntimeException");            throw new RuntimeException("There was an error.");
        }        return "hello bolts";
    }
}, Task.BACKGROUND_EXECUTOR).onSuccess(new Continuation<String, Void>() {    @Override
    public Void then(Task<String> task) throws Exception {
        XLog.d(Thread.currentThread().getName() + " onSuccess");        return null;
    }
}, Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Void, Void>() {    @Override
    public Void then(Task<Void> task) throws Exception {        if (task.isFaulted()) {
            XLog.e(Thread.currentThread().getName() + " error");            return null;
        }
        XLog.d(Thread.currentThread().getName() + " done");        return null;
    }
}, Task.UI_THREAD_EXECUTOR);请问这里的打印结果是如何呢?
- A: onSuccess 
- B: error 
- C: done 
- D: onSuccess & done 
正确答案是B
小结
android多线程的方案还有诸如: yigit/android-priority-jobqueue, 不过经过实测, 和Bolts-Android比较起来, android-priority-jobqueue还是"略重量级"了一些, 如果你有更好的方案和实现, 欢迎留言和分享
作者:诺之林
链接:https://www.jianshu.com/p/fcfb541568af
共同学习,写下你的评论
评论加载中...
作者其他优质文章
 
                 
             
			 
					 
					