Android开发之利用ConditionVariable同步线程结果

概述

在我们日常开发当中有时会遇到这样的场景,例如一个操作依赖2个数据,而这2个数据是通过2个线程分别计算得到的,而这个2个计算结果完成的先后顺序是不能事先确定的,那我们就得想办法同步这2个线程的结果。

解决方案

方案1

使用在各个工作线程都检查执行条件是否满足需求的方式。

1:为这个2个线程操作分别定义一个flag,用来指示这个2个线程是否完成了自己的任务.
2:在需要使用这个2个线程的结果的那个方法里面判断这个2个flag是否同时为真,同时为真说明我们已经得到了所有依赖的数据了,执行相应的操作即可。
3:最后就是必须在每个线程中调用这个方法,因为我们不知道哪个线程先完成任务,所以需要在每个工作线程中检查。

方案2

使用线程同步技术,我们此处使用Android 提供的ConditionVariable来同步线程。
1:为线程1操作定义一个用于指示任务是否完成的flag
2:在线程2中在完成自己的工作后检查线程1flag,如果为真说明两个线程都完成了自己的工作。如果线程1的flag为假则表示,线程1还没有完成自己的工作,所以线程2需要等待其完成,此处就是使用ConditionVariable来完成的。
3:线程1完成了自己的工作后,就会解除线程2的等待状态,继续执行最后的任务。

ConditionVariable示例

基本知识

ConditionVariable提供的一种依据条件变量锁定的机制。本身非常简单,只有4个公有方法。

MethodReturnTypeDescription
block()voidBlock the current thread until the condition is opened.
block(long timeout)booleanBlock the current thread until the condition is opened or until timeout milliseconds have passed.
close()voidReset the condition to the closed state.
open()voidOpen the condition, and release all threads that are blocked.

在处于close状态的情况下,我们可以使用block()来阻塞线程,使用open()来打开线程。

代码示例

假设我们现在有两个工作线程,每个工作线程耗时不能事先确定,而只有当着两个线程的工作都完成后我们才能将我们想要的结果显示在一个TextView上。

如下图所示:
这里写图片描述

public class MainActivity extends AppCompatActivity {

    private volatile  String t1Des="t1",t2Des="t2";
    private volatile  boolean firstThreadFinish=false;
    private TextView tvResult;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvResult=findViewById(R.id.showResult);
        findViewById(R.id.btnStartWork).setOnClickListener(clickListener);
    }

    private void startWork(){
        final ConditionVariable completed=new ConditionVariable();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    long t=1000+new Random().nextInt(5)*1000;
                    Thread.sleep(t);
                    t1Des=String.format("线程:%s 耗时:%s",Thread.currentThread().getName(),t);
                    firstThreadFinish=true;
                    completed.open();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    long t=1000+new Random().nextInt(5)*1000;
                    Thread.sleep(t);
                    t2Des=String.format("线程:%s 耗时:%s",Thread.currentThread().getName(),t);
                    try {
                        if (firstThreadFinish==false)
                            completed.block();
                        MainActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                allFinished();
                            }
                        });
                    } finally {
                        completed.open();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void allFinished(){
        tvResult.setText(t1Des+"\n\n"+t2Des);
    }
    private View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btnStartWork:
                    tvResult.setText("正在计算...");
                    firstThreadFinish=false;
                    startWork();
                    break;
                default:
                    break;
            }
        }
    };
}

我们在第二个线程中使用firstThreadFinish这个flag来判断第一个线程的工作是否已经完成,如果没有完成则锁定第二个线程,等待第一个线程。

 if (firstThreadFinish==false)
     completed.block();

当在第一线程完成了自己的工作后,就将firstThreadFinish设置为真,并且解除第二个线程的锁定状态。

firstThreadFinish=true;
completed.open();

这样我们就达到了同步两个线程结果的目的。

总结

ConditionVariable是一种简单的线程锁定机制,其在处理两个线程的情况下比较方便,当将上面的工作线程扩展到10个,那我们就需要9个ConditionVariable来完成,那样就非常复杂了。

当出现多个线程需要同步的情况,最为简单的还是循环等待,例如

while!(t1Flag&&t2Flag&&t3Flag...)){
    Thread.sleap(200);
}

技术无好坏,关键看是否合适当前情况。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuSheng007

亲爱的猿猿,难道你又要白嫖?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值