是否有过我们不会对线程之间共享的对象的类成员使用 volatile 的情况?我的理解是 volatile 关键字确保对象值不被线程缓存,而是始终从内存中读取,但不将其标记为 volatile 并不意味着它将始终被线程缓存。所以我的问题是,我们是否可以通过不将此类标记为 volatile 来保证任何事情,或者代码是否会对随机行为开放?
编辑:我知道对所有事情都使用 volatile 并不能保证我的逻辑的正确性。我的问题更多是理论上的,是我理解 Java 内存模型的尝试。
是否有过我们不会对线程之间共享的对象的类成员使用 volatile 的情况?我的理解是 volatile 关键字确保对象值不被线程缓存,而是始终从内存中读取,但不将其标记为 volatile 并不意味着它将始终被线程缓存。所以我的问题是,我们是否可以通过不将此类标记为 volatile 来保证任何事情,或者代码是否会对随机行为开放?
编辑:我知道对所有事情都使用 volatile 并不能保证我的逻辑的正确性。我的问题更多是理论上的,是我理解 Java 内存模型的尝试。
首先,您不应该用缓存来解释并发性。由于版本 2 java 内存模型更正式并且要求更弱。所以,这一切都是关于先发生的顺序。
如果您需要对某些变量进行并发访问,则必须通过发生前对写入和读取进行排序。这是最重要的事情。Volatile 只是这种排序的一种实现方式。
因此,您可以使用任何具有happens-before语义的操作来代替volatile。来自JLS:
监视器上的解锁发生在该监视器上的每个后续锁定之前。
线程上的 start() 调用发生在已启动线程中的任何操作之前。
线程中的所有操作都发生在任何其他线程
从该线程上的 join() 成功返回之前。
任何对象的默认初始化发生在程序的任何其他
操作(默认写入除外)之前。
至少不可变对象永远不需要任何类型的同步。因此,对不可变类的字段使用volatile是没有意义的。
如果您不将变量声明为易失性,并且在访问它之前不进行任何类型的互斥锁,那么是的,您总是将自己暴露于不可预测的行为和竞争条件/死锁。