BRG*_*BRG 5 java synchronization kotlin kotlin-android-extensions kotlin-coroutines
我一直在尝试 Kotlin 同步,但从文档中我不明白锁定机制如何在公共资源上的线程同步上工作,因此尝试编写这段代码,这使我的理解进一步复杂化。
fun main() {
val myList = mutableListOf(1)
thread {
myList.forEach {
while (true) {
println("T1 : $it")
}
}
}
thread {
synchronized(myList) {
while (true) {
myList[0] = 9999
println("**********\n**********\n**********\n")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
myList是所讨论的公共资源。
第一个线程是一个简单的读取操作,我打算将资源保持在读取模式下。第二个是另一个线程,它请求锁定以修改公共资源。
尽管第一个线程不包含任何同步,但我希望它能够在内部处理此问题,以便在某个函数(例如map或 )forEach正在对资源进行操作时,另一个线程不应该能够锁定它,否则正在迭代的元素可能会发生变化当map/forEach正在进行时(即使该操作可能会暂停一段时间,而另一个线程对其具有锁定)。
我看到的输出显示两个线程正在并行执行。它们都分别打印列表中的第一个元素和星星。但在第二个线程中,即使正在打印星星,myList[0]也永远不会设置为 9999,因为第一个线程继续打印 1。
线程和同步是 JVM 功能,并非 Kotlin 特有的。如果您懂 Java,那么有很多资源可以完整地解释它们。但简短的回答是:它们的级别相当低,而且很难正确执行,因此请谨慎行事。如果更高级别的构造(工作队列/执行器、映射/归约、参与者...)或不可变对象可以满足您的需求,那么如果您使用它,生活会更轻松!
但这是基础知识。首先,在JVM中,每个对象都有一个锁,它可以用来控制对某些东西的访问。(通常是锁所属的对象,但不一定是...)锁可以由特定线程中的代码获取;当它持有该锁时,任何其他尝试获取该锁的线程都将阻塞,直到第一个线程释放它。
这几乎就是全部了!关键字synchronised(实际上是一个函数)用于声明锁;属于给定对象的对象或(如果没有给定)“this”对象。
请注意,持有锁会阻止其他线程持有该锁;它不会阻止任何其他事情。所以恐怕你的期望是错误的。这就是为什么您会看到线程愉快地同时运行。
理想情况下,编写每个类时都会考虑它如何与多线程交互;它可以将自己记录为“不可变”(无需担心可变状态)、“线程安全”(同时从多个线程安全调用)、“有条件线程安全”(如果遵循某些模式,则可以从多个线程安全调用)到)、“线程兼容”(不采取特殊预防措施,但调用者可以进行自己的同步以确保安全)或“线程敌对”(无法从多个线程使用)。但实际上,大多数人并不这样做。
事实上,大多数都是线程兼容的。这适用于大部分 Java 和 Kotlin 集合类。所以你可以做你自己的同步(根据你的synchronized块);但是您必须注意同步对列表的每个可能的访问 - 否则,竞争条件可能会使您的列表处于不一致的状态。
(这可能不仅仅意味着某个地方有一个不可靠的值。我有一个服务器应用程序,它的一个线程陷入了繁忙的循环中——消耗了 100% 的 CPU,但从未继续执行其余代码——因为我让一个线程更新 HashMap,而另一个线程正在读取它,而我错过了其中一个线程的同步。最令人尴尬的。)
所以,正如我所说,如果你可以使用更高级别的构造来代替,你的生活会更轻松!
第二个线程不会更改第一个列表元素的值,因为==意味着比较,而不是分配。您需要使用=tio 更改值,例如myList[0] = 9999。但是,在您的代码中,不能保证第二个线程的更改将在第一个线程中可见,因为线程一个未在 上同步myList。
如果您的目标是 JVM,您应该阅读有关 JVM 内存模型的信息,例如什么是@Volatile. 您当前的方法不能保证第一个线程会看到第二个线程的更改。您可以将代码简化为以下损坏的示例:
var counter = 1
fun main() {
thread {
while (counter++ < 1000) {
println("T1: $counter")
}
}
thread {
while (counter++ < 1000) {
println("T2: $counter")
}
}
}
Run Code Online (Sandbox Code Playgroud)
它可以打印奇怪的结果,例如:
var counter = 1
fun main() {
thread {
while (counter++ < 1000) {
println("T1: $counter")
}
}
thread {
while (counter++ < 1000) {
println("T2: $counter")
}
}
}
Run Code Online (Sandbox Code Playgroud)
这可以通过几种方式来解决,例如通过使用同步。
| 归档时间: |
|
| 查看次数: |
4816 次 |
| 最近记录: |