1. 适用范围
在业务逻辑中有的时候会遇到一些等待多个子线程的返回结果再执行某个功能的情况,这种处理在代码上体现出来就不好阅读和维护,针对这一系列痛点建议java使用CyclicBarrier同步屏障,kotlin使用携程来处理,过程方便阅读,维护。
2. 场景
在正常使用情况下,如果事件放在子线程那么会出现,不确定时间,并行无法统一处理结果的问题如下图 ↓
我们理想中的流程应该是这样的,统一处理结果 ↓
CyclicBarrier
使用CyclicBarrier完成线程同步
4. GlobalScope
Kotlin使用协程完成线程同步(运行在子线程)
5. GlobalScope - withContext
Kotlin使用协程完成线程同步(运行在主线程)
代码
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.Button
import com.chenenyu.router.annotation.Route
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CyclicBarrier
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import android.os.Looper
import kotlinx.coroutines.*
import java.lang.Runnable
/**
* @fileName: CyclicBarrierActivity
* @date: 2019/9/9 19:07
* @auther: YuanShuai
* @tag: class//
* @describe:
**/
@Route("cyclicBarrier")
class CyclicBarrierActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cyclicbarrier)
findViewById<Button>(R.id.btn).apply {
setOnClickListener {
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber}) " +
"currentThread=" + isOnMainThread()
)
var cb = CyclicBarrier()
cb.count()
}
}
findViewById<Button>(R.id.btn2).apply {
setOnClickListener {
GlobalScope.launch {
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber})" +
"GlobalScope - isOnMainThread=" + isOnMainThread()
)
var i1 = thead1()
var i2 = thead2()
var i3 = thead3()
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber})" +
" 协程平均数=${(i1 + i2 + i3) / 3}"
)
}
}
}
findViewById<Button>(R.id.btn3).apply {
setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber})" +
"GlobalScope - isOnMainThread=" + isOnMainThread()
)
var number = 0
var number2 = 0
var number3 = 0
//当前线程是什么 这里面是什么线程 不需要suspend挂起方法
withContext(coroutineContext) {
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber})" +
"GlobalScope - isOnMainThread=" + isOnMainThread()
)
number = mainThread()
number2 = mainThread2()
number3 = mainThread3()
}
Log.e(
"CyclicBarrierActivity",
"(onCreate:${Thread.currentThread().stackTrace[2].lineNumber})" +
"主线程协程平均数=${(number + number2 + number3) / 3}"
)
}
}
}
}
fun mainThread(): Int {
var num = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(mainThread:${Thread.currentThread().stackTrace[2].lineNumber}) num=$num"
)
return num
}
fun mainThread2(): Int {
var num = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(mainThread:${Thread.currentThread().stackTrace[2].lineNumber}) num=$num"
)
return num
}
fun mainThread3(): Int {
var num = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(mainThread:${Thread.currentThread().stackTrace[2].lineNumber}) num=$num"
)
return num
}
fun thead1(): Int {
var n1 = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(thead1:${Thread.currentThread().stackTrace[2].lineNumber}) " +
"num=$n1"
)
return n1
}
suspend fun thead2(): Int {
delay(2000)
var n1 = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(thead1:${Thread.currentThread().stackTrace[2].lineNumber}) " +
"num=$n1"
)
return n1
}
suspend fun thead3(): Int {
delay(5000)
var n1 = (Math.random() * 40 + 60).toInt()
Log.e(
"CyclicBarrierActivity",
"(thead1:${Thread.currentThread().stackTrace[2].lineNumber}) " +
"num=$n1"
)
return n1
}
private fun isOnMainThread(): Boolean {
return Looper.myLooper() == Looper.getMainLooper()
}
class CyclicBarrier : Runnable {
override fun run() {
var result = 0
var set: MutableSet<String> = map.keys
for (s in set) {
result += Integer.parseInt(map[s].toString())
}
Log.e(
"CyclicBarrierActivity",
"(run:${Thread.currentThread().stackTrace[2].lineNumber})" +
" 平均数为${result / 3}分"
)
}
var threadPool: ExecutorService = Executors.newFixedThreadPool(3)
var cb: java.util.concurrent.CyclicBarrier = CyclicBarrier(3, this)
var map = HashMap<String, Int>()
fun count() {
threadPool.execute {
var score = (Math.random() * 40 + 60).toInt()
map[Thread.currentThread().name] = score
Log.e(
"CyclicBarrierActivity",
"num=$score "
)
cb.await()
}
threadPool.execute {
Thread.sleep(2000)
var score = (Math.random() * 40 + 60).toInt()
map[Thread.currentThread().name] = score
Log.e(
"CyclicBarrierActivity",
"num=$score "
)
cb.await()
}
threadPool.execute {
Thread.sleep(5000)
var score = (Math.random() * 40 + 60).toInt()
map[Thread.currentThread().name] = score
Log.e(
"CyclicBarrierActivity",
"num=$score "
)
cb.await()
}
}
}
}