Kotlin:该如何实现多线程同步?

val t1 = Thread { s1 = task1() }

val t2 = Thread { s2 = task2() }

t1.start()

t2.start()

t1.join()

t2.join()

task3(s1, s2)

}

方式2:线程锁

主要包括:Synchronized、ReentrantLock、CountDownLatch、CyclicBarrier

Synchronized

@Test

fun test_synchrnoized() {

lateinit var s1: String

lateinit var s2: String

Thread {

synchronized(Unit) {

s1 = task1()

}

}.start()

s2 = task2()

synchronized(Unit) {

task3(s1, s2)

}

}

这里需要特别注意的是:为了同步多个并行任务的结果则需要声明n个锁, 即需嵌套n个 synchronized

ReentrantLock

相对于Synchronized,ReentrantLock的使用则不会出现嵌套 synchrnoized 的问题,但仍需创建多个 lock 从而管理多个不同的线程任务。

fun test_ReentrantLock() {

lateinit var s1: String

lateinit var s2: String

val lock = ReentrantLock()

Thread {

lock.lock()

s1 = task1()

lock.unlock()

}.start()

s2 = task2()

lock.lock()

task3(s1, s2)

lock.unlock()

}

这里需要额外说明的是,阻塞队列BlockingQueue内部是通过ReentrantLock实现的,所以其也能实现线程同步,但其应用场景是:生产/消费场景中的同步

fun test_blockingQueue() {

lateinit var s1: String

lateinit var s2: String

val queue = SynchronousQueue()

Thread {

s1 = task1()

queue.put(Unit)

}.start()

s2 = task2()

queue.take()

task3(s1, s2)

}

CountDownLatch

JUC 中的锁大都基于 AQS 实现的,可以分为独享锁和共享锁。ReentrantLock 就是一种独享锁。相比之下,共享锁更适合本场景,不需为了每个任务都创建单独的锁。

@Test

fun test_countdownlatch() {

lateinit var s1: String

lateinit var s2: String

val cd = CountDownLatch(2)

Thread() {

s1 = task1()

cd.countDown()

}.start()

Thread() {

s2 = task2()

cd.countDown()

}.start()

cd.await()

task3(s1, s2)

}

CyclicBarrier

原理:让一组线程到达一个同步点后再一起继续运行,其中任意一个线程未达到同步点,其他已到达的线程均会被阻塞。

@Test

fun test_CyclicBarrier() {

lateinit var s1: String

lateinit var s2: String

val cb = CyclicBarrier(3)

Thread {

s1 = task1()

cb.await()

}.start()

Thread() {

s2 = task1()

cb.await()

}.start()

cb.await()

task3(s1, s2)

}

需要特别注意的是:与 CountDownLatch 的区别在于 CountDownLatch 是一次性的,而 CyclicBarrier 可以被重置后循环利用

方式3:CAS

原理:基于 CAS 的原子类计数

应用场景:一些cpu密集型的短任务同步(因为会比较损耗资源)

fun test_cas() {

lateinit var s1: String

lateinit var s2: String

val cas = AtomicInteger(2)

Thread {

s1 = task1()

cas.getAndDecrement()

}.start()

Thread {

s2 = task2()

cas.getAndDecrement()

}.start()

while (cas.get() != 0) {}

task3(s1, s2)

}

这里需要特别说明的是,看到 CAS 的无锁实现,很多人会想到 volatile:并非线程安全,因为volatile 能保证可见性,但是不能保证原子性,cnt-- 并非线程安全,需要加锁操作

fun test_Volatile() {

lateinit var s1: String

lateinit var s2: String

Thread {

s1 = task1()

cnt–

}.start()

Thread {

s2 = task2()

cnt–

}.start()

while (cnt != 0) {

}

task3(s1, s2)

}

方式4:Future

Java 1.5 开始提供了一种可以在任务执行结束时返回结果的线程同步方式:Callable 和 Future 。即不需通过定义变量来记录结果了。

// 通过 future.get(),可以同步等待结果返回,写起来非常方便

fun test_future() {

val future1 = FutureTask(Callable(task1))

val future2 = FutureTask(Callable(task2))

Executors.newCachedThreadPool().execute(future1)

Executors.newCachedThreadPool().execute(future2)

task3(future1.get(), future2.get())

}

这里需要特别说明的是,future.get() 虽然方便,但是会阻塞线程。所以在 Java 8 中引入了 CompletableFuture :他实现了 Future 接口的同时实现了 CompletionStage 接口,即可针对多个 CompletionStage 进行逻辑组合、实现复杂的异步编程。以回调的形式避免了线程阻塞

fun test_CompletableFuture() {

CompletableFuture.supplyAsync(task1)

文末

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

[外链图片转存中…(img-3bJQXGda-1715672863517)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-Kq75ELEZ-1715672863519)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值