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()
}
}
}
}