zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【Kotlin 协程】协程并发安全问题 ( 使用 Atomic 并发安全类型 | 使用 Channel 通道 | 使用 Mutext 轻量级锁 | 使用 Semaphore 轻量级信号量 )

Kotlin并发安全 类型 协程 轻量级 通道 channel
2023-09-14 09:07:26 时间





一、协程不安全数据访问



在多个线程中 同时访问 相同数据 , 就会出现 线程不安全 访问 的问题 ;

如果多个协程中 , 同时访问相同数据 , 同样会出现 不安全数据访问 问题 ;


协程不安全数据访问代码示例 : 同时开启 100000 个协程 , 对相同的 int 值进行累加 , 等所有协程访问完毕 , 查看最终结果 , 发现最终累加不足 100000 ;

package kim.hsl.coroutine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            var count = 0
            List(100000) {
                GlobalScope.launch {
                    count++
                }
            }.joinAll()
            println(count)
        }
    }
}

执行结果 :

15:30:41.957 System.out   kim.hsl.coroutine     I  99978

在这里插入图片描述





二、使用 Atomic 并发安全类型



使用 Atomic 原子类型数据 应对 协程不安全访问 问题 ;


代码示例 :

package kim.hsl.coroutine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.concurrent.atomic.AtomicInteger

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            var count = AtomicInteger(0)
            List(100000) {
                GlobalScope.launch {
                    count.incrementAndGet()
                }
            }.joinAll()
            println(count)
        }
    }
}

执行结果 :

15:57:02.984 System.out   kim.hsl.coroutine     I  100000

在这里插入图片描述





三、使用 Channel 通道



使用 Channel 通道进行协程间通信 , 该 Channel 通道是并发安全的 ;

参考如下博客 :





四、使用 Mutext 轻量级锁



使用 Mutext 轻量级锁 , 加锁 Mutext#lock , 解锁 Mutext#unlock , 如果执行时获取不到 Mutext 锁 , 会挂起等待 Mutext 锁释放 , 不会阻塞线程 ;


首先 , 创建 Mutex 锁 实例对象 ;

val mutex = Mutex()

然后 , 将协程中的并发代码定义在 mutex.withLock 代码块内 ;

GlobalScope.launch {
    mutex.withLock {
        count++
    }
}

代码示例 :

package kim.hsl.coroutine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.util.concurrent.atomic.AtomicInteger

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            var count = 0
            val mutex = Mutex()
            List(100000) {
                GlobalScope.launch {
                    mutex.withLock {
                        count++
                    }
                }
            }.joinAll()
            println(count)
        }
    }
}

执行结果 :

15:57:02.984 System.out   kim.hsl.coroutine     I  100000

在这里插入图片描述





五、使用 Semaphore 轻量级信号量



使用 Semaphore 轻量级信号量 , 可以同时定义多个 信号量 , 协程获取到 对应 信号量时才能执行并发任务 ;


首先 , 创建 Semaphore 信号量 实例对象 ;

val semaphore = Semaphore(1)

然后 , 将协程中的并发代码定义在 semaphore.withPermit 代码块内 ;

GlobalScope.launch {
    semaphore.withPermit {
        count++
    }
}

代码示例 :

package kim.hsl.coroutine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            var count = 0
            val semaphore = Semaphore(1)
            List(100000) {
                GlobalScope.launch {
                    semaphore.withPermit {
                        count++
                    }
                }
            }.joinAll()
            println(count)
        }
    }
}

执行结果 :

19:10:54.612 System.out   kim.hsl.coroutine     I  100000

在这里插入图片描述