Android中异步转同步(主线程等待子线程)方法总结 您所在的位置:网站首页 androidstudio返回上一步 Android中异步转同步(主线程等待子线程)方法总结

Android中异步转同步(主线程等待子线程)方法总结

2023-08-01 13:54| 来源: 网络整理| 查看: 265

前言

Android日常开发中,平时获取子线程返回结果以异步回调的方式获取返回到主线程,其实也可以通过某种方法转为同步返回,不过要慎用在UI主线程中使用,以防ANR。 应用场景: 1. 单个线程处理结果返回到主线程 2. 多个子线程并发请求,最终合并返回结果到主线程 下面介绍8种方法实现主线程等待子线程: 介绍之前先贴出测试类NetRequest :

/** * 模拟网络请求类 */ private static class NetRequest implements Runnable, Callable { private String msg; private int way; public NetRequest() { way = -1; } private CountDownLatch countDownLatch; public NetRequest(int way, CountDownLatch countDownLatch) { this.way = way; this.countDownLatch = countDownLatch; } private CyclicBarrier cyclicBarrier; public NetRequest(int way, CyclicBarrier cyclicBarrier) { this.way = way; this.cyclicBarrier = cyclicBarrier; } private Semaphore semaphore; public NetRequest(int way, Semaphore semaphore) { this.way = way; this.semaphore = semaphore; } private Phaser phaser; public NetRequest(int way, Phaser phaser) { this.way = way; this.phaser = phaser; } @Override public void run() { switch (way) { case 1: msg = createData(); if (countDownLatch != null) { countDownLatch.countDown();//计数减1 } break; case 2: msg = createData(); if (cyclicBarrier != null) { try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } break; case 3: if (semaphore != null){ msg = createData(); semaphore.release(); } break; case 4: if (phaser != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { msg = createData(); phaser.arriveAndDeregister(); } break; default: msg = createData(); break; } } private String createData() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } msg = "hello world:" + System.currentTimeMillis(); return msg; } public String getMsg() { return msg; } @Override public String call() throws Exception { return createData(); } }

特别注意:以下代码在主线程执行操作,即可验证结果

1.使用轮询

NetRequest netRequest = new NetRequest(); Thread thread = new Thread(netRequest); thread.start(); while (true) { String msg = netRequest.getMsg(); if (!TextUtils.isEmpty(msg)) { textView.setText(netRequest.getMsg());//输出: hello world和时间戳 break; } }

缺点:如果子线程因某种原因永远执行不完,导致永远拿到不返回结果,容易ANR.

2.使用sleep

直接在主线程睡眠,等待子线程返回

NetRequest netRequest = new NetRequest(); Thread thread = new Thread(netRequest); thread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } textView.setText(netRequest.getMsg());

缺点:不明确子线程执行时间情况下,不一定能拿得到返回结果

3.使用join

阻塞调用此方法的线程进入 TIMED_WAITING 状态,直到线程完成。通常用于在main()主线程内,等待其它线程完成再结束main()主线程。

NetRequest netRequest = new NetRequest(); Thread thread = new Thread(netRequest); thread.start(); try { thread.join(); String msg = netRequest.getMsg(); textView.setText(msg); } catch (InterruptedException e) { e.printStackTrace(); }

4.使用Future‘

NetRequest netRequest = new NetRequest(); ExecutorService exec = Executors.newFixedThreadPool(1); Future task = exec.submit((Callable) netRequest); try { String s = task.get();//阻塞等待 textView.setText(s); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }’

从上面可知,这是线程创建的又一种实现方式,只不过是阻塞异步的

5.使用CountDownLatch

CountDownLatch是一种java.util.concurrent包下一个同步工具类,它允许一个或多个线程等待直到在其他线程中一组操作执行完成。CountDownLatch 是计数器, 线程完成一个就记一个, 就像报数一样, 只不过是递减的.

CountDownLatch countDownLatch = new CountDownLatch(1); NetRequest netRequest = new NetRequest(1, countDownLatch); Thread thread = new Thread(netRequest); thread.start(); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } String msg = netRequest.getMsg(); textView.setText(msg);

6.使用同步屏障CyclicBarrier

JDK1.5开始提供的并发编程辅助工具类,也可以用于多线程。线程间同步阻塞是使用的是ReentrantLock,可重入锁。

CountDownLatch和CyclicBarrier区别: CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待,类似有福同享,有难同当

CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> Log.i("SIMPLE_LOGGER", "开始执行")); NetRequest netRequest = new NetRequest(2, cyclicBarrier); Thread thread = new Thread(netRequest); thread.start(); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } String msg = netRequest.getMsg(); textView.setText(msg);

7.使用信号量Semaphore

这个也是Java并发包中另外一个重量级的类Semaphore,这个类从字面意义上理解是"信号量"。平时自己用得不多。举个例子,假如10个人比赛100米冲刺,有5条赛道,被安排到的5个人才能在跑道上比赛,其余等待。

Semaphore与CountDownLatch相似,不同的地方在于Semaphore的值被获取到后是可以释放的,并不像CountDownLatch那样一直减到底。它也被更多地用来限制流量,类似阀门的 功能。如果限定某些资源最多有N个线程可以访问,那么超过N个主不允许再有线程来访问,同时当现有线程结束后,就会释放,然后允许新的线程进来。

Semaphore semaphore = new Semaphore(0);//默认为非公平信号量,当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发 NetRequest netRequest = new NetRequest(3, semaphore); Thread thread = new Thread(netRequest); thread.start(); try { semaphore.acquire(); String msg = netRequest.getMsg(); textView.setText(msg); } catch (InterruptedException e) { e.printStackTrace(); }

8.使用移相器Phaser

也是一个重量级并发类,jdk7被引入,用来解决控制多个线程分阶段共同完成任务的情景问题。其作用相比CountDownLatch和CyclicBarrier更加灵活。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { Phaser phaser = new Phaser(); phaser.register(); NetRequest netRequest = new NetRequest(4, phaser); Thread thread = new Thread(netRequest); thread.start(); phaser.register(); phaser.arriveAndAwaitAdvance(); String msg = netRequest.getMsg(); textView.setText(msg); } 总结

除了上面几种方法,估计还有其它实现方法,有待研究。这次只是简单介绍用法,如果想更深入了解上面类的用法及其原理,可以到java.util.concurrent包下找到相关类研究或者网上研究。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有