概述
在我们日常开发当中有时会遇到这样的场景,例如一个操作依赖2个数据,而这2个数据是通过2个线程分别计算得到的,而这个2个计算结果完成的先后顺序是不能事先确定的,那我们就得想办法同步这2个线程的结果。
解决方案
方案1
使用在各个工作线程都检查执行条件是否满足需求的方式。
1:为这个2个线程操作分别定义一个flag
,用来指示这个2个线程是否完成了自己的任务.
2:在需要使用这个2个线程的结果的那个方法里面判断这个2个flag
是否同时为真,同时为真说明我们已经得到了所有依赖的数据了,执行相应的操作即可。
3:最后就是必须在每个线程中调用这个方法,因为我们不知道哪个线程先完成任务,所以需要在每个工作线程中检查。
方案2
使用线程同步技术,我们此处使用Android 提供的ConditionVariable来同步线程。
1:为线程1操作定义一个用于指示任务是否完成的flag
2:在线程2中在完成自己的工作后检查线程1的flag
,如果为真说明两个线程都完成了自己的工作。如果线程1的flag为假则表示,线程1还没有完成自己的工作,所以线程2需要等待其完成,此处就是使用ConditionVariable
来完成的。
3:线程1完成了自己的工作后,就会解除线程2的等待状态,继续执行最后的任务。
ConditionVariable示例
基本知识
ConditionVariable提供的一种依据条件变量锁定的机制。本身非常简单,只有4个公有方法。
Method | ReturnType | Description |
---|---|---|
block() | void | Block the current thread until the condition is opened. |
block(long timeout) | boolean | Block the current thread until the condition is opened or until timeout milliseconds have passed. |
close() | void | Reset the condition to the closed state. |
open() | void | Open 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);
}
技术无好坏,关键看是否合适当前情况。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14771.html