如果我有一个变量,多个线程读取并且只有一个线程写入,那么是否需要锁定该变量?如果一个线程尝试读取并且另一个线程尝试同时写入,它会崩溃吗?Java中并发读取/写入变量
回答
并发担忧并不崩溃,但你看到的版本的数据。
如果共享变量原子写的,这是可能的,因为当你认为你的(作家)线程已经更新了一个变量(读者)线程读取一个不完整的数值。您可以使用易变关键字来防止读者线程在这种情况下读取过时的值。
如果写入操作不是原子的(例如,如果它是某种组合对象,并且您一次只写一些数据,而其他线程理论上可以读取它),那么您的担心也会有些读者线程可能会看到处于不一致状态的变量。您可以通过在写入时缓存对变量的访问(缓慢)或确保您正在以原子方式写入来防止这种情况。
请注意,volatile不是原子的,这意味着使用64位的double和long可以在32位为旧值且32位为新值的不一致状态下读取。此外,易失性阵列不会使阵列条目变得不稳定。强烈建议使用java.util.concurrent中的类。
简单的答案是肯定的,你需要同步。
如果你写一个领域,如果没有某种形式的同步,从其他地方读它,你的程序可以看到不一致的状态,很可能是错误的。你的程序不会崩溃,但可以看到旧的或新的或者(在长时间和双打的情况下)半个新旧数据。
虽然我说“某种形式的同步”,但我更确切地说是指在写入和读取位置之间创建“发生之前”关系(又名存储障碍)的东西。同步或java.util.concurrent.lock类是创建此类事物最明显的方式,但所有并发集合通常也提供类似的保证(检查javadoc以确保)。例如,执行put和take一个并发队列将创建一个before-before关系。
标记字段挥发性阻止你看到不一致的引用(长撕裂),并保证所有的线程将“看”的写操作。但是,易失性字段写入/读取不能与更大原子单元中的其他操作组合。 Atomic类处理常见的组合操作,如比较和设置或读取和增量。同步或其他java.util.concurrent同步器(CyclicBarrier等)或锁应该用于更大的排他性领域。
从简单的是开车的,也有更多的“不,如果你真的知道你在做什么”的情况。举两个例子:
1)一个字段是最后的也是唯一的建设过程中写入的特殊情况。其中一个例子是,当您填充预先计算的缓存时(想到一个Map,其中键是众所周知的值,值是预先计算的派生值)。如果在构建之前将其构建到字段中,并且该字段是最终的,并且以后再也不写入,则构造函数的结尾将执行“最终字段冻结”,并且后续读取不需要同步。
2)被覆盖在有效的Java的“活泼单个检查”图案的情况下。规范示例在java.lang.String中。hashCode()方法。首次调用hashCode()并将其缓存到未同步的本地字段中时,字符串的哈希字段将被延迟计算。基本上,多个线程可以竞争来计算这个值并且设置在其他线程上,但是因为它被一个知名的哨兵(0)保护并且总是计算相同的值(所以我们不关心哪个线程“获胜”或者是否多重做),这实际上是保证没问题。
更长的参考(我写的):http://refcardz.dzone.com/refcardz/core-java-concurrency
- 1. 写入并读取矢量到Java中的序列化文件?
- 2. 写入环境变量,并从相同的过程中读取
- 3. 从全局变量读取和写入
- 4. 同时读取和写入变量
- 5. 并发读取和写入文件
- 6. 并发读取和写入BlockingQueue
- 7. 使用Powershell读取Excel数据并写入变量
- 8. 在读取行时,awk $行并写入变量
- 9. Java:文件读取/写入
- 10. Java - 文件读取/写入
- 11. 写入并读取Android
- 12. 写入并读取到SDcard
- 13. 并行读取和写入
- 14. 并行读取/写入ADLA
- 15. Java中的并发读/写文件
- 16. Java:并发读取InputStream
- 17. 并发读写OpenMp中的共享变量
- 18. 如何从Excel中读取并写入量角器的Excel中?
- 19. 在java中读取和写入xml
- 20. 在CUDA中合并读取/写入
- 21. NSDocumentDirectory - 写入并从文件中读取
- 22. 并发读写
- 23. 从文件读取并写入到java文件中
- 24. Java - 读取键盘输入并将其写入文本文件
- 25. 从Java中读取xsl转换变量
- 26. 在Java读取Excel中,变量是空
- 27. 向Ocaml中的文件写入和读取自定义变量
- 28. 在PHP中跨脚本读取和写入全局变量
- 29. 如何读取/写入UWP中父框架的变量?
- 30. 从模块B读取和写入模块A中的变量
我不知道,双打和多头可以处于不一致的状态可以看出。那么这是否也适用于64位系统上的(64位)引用,并且意味着您可以获得无效的引用? –
由于解锁写入导致的不一致的长整数和双整数通常被称为“长期撕裂”。在64位jvm中由64位指针支持的对象引用不受此问题的影响。也就是说,对象引用的“写入”总是原子的。 –
易变“长”和“双”值**是原子**,与非易失性“长”和“双”值(可能不是原子)相反。即使非易失性,其他原始值也是原子。 –