- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当我阅读Brian Goetz的《实践中的Java并发性》时,我回想起他在有关可见性的章节中说“另一方面,即使不使用同步来发布对象引用,也可以安全地访问不可变对象(immutable对象)”。
我认为这意味着,如果发布一个不可变的对象,则所有可能使用它们的线程(包括可变的最终引用)对其他可能使用它们的线程都是可见的,并且至少是该对象完成构造之前的最新消息。
现在,我在https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html中读到
“现在,说完所有这些,如果在线程构造一个不可变对象(immutable对象)(即,一个仅包含最终字段的对象)之后,您想要确保在所有其他线程中都能正确看到该对象,需要使用同步。没有其他方法可以确保例如对不可变对象(immutable对象)的引用将被第二个线程看到。确保从最终字段获得程序的保证应经过认真而深入的了解如何在代码中管理并发。”
他们似乎相互矛盾,我不确定该相信哪个。
我还读到,如果所有字段都是最终字段,那么即使对象不是说不可变的,我们也可以确保安全发布。
例如,由于这种保证,我一直认为,在发布此类的对象时,Brian Goetz的并发实践中的这段代码很好。
@ThreadSafe
public class MonitorVehicleTracker {
@GuardedBy("this")
private final Map<String, MutablePoint> locations;
public MonitorVehicleTracker(
Map<String, MutablePoint> locations) {
this.locations = deepCopy(locations);
}
public synchronized Map<String, MutablePoint> getLocations() {
return deepCopy(locations);
}
public synchronized MutablePoint getLocation(String id) {
MutablePoint loc = locations.get(id);
return loc == null ? null : new MutablePoint(loc);
}
public synchronized void setLocation(String id, int x, int y) {
MutablePoint loc = locations.get(id);
if (loc == null)
throw new IllegalArgumentException("No such ID: " + id);
loc.x = x;
loc.y = y;
}
private static Map<String, MutablePoint> deepCopy(
Map<String, MutablePoint> m) {
Map<String, MutablePoint> result =
new HashMap<String, MutablePoint>();
for (String id : m.keySet())
result.put(id, new MutablePoint(m.get(id)));
return Collections.unmodifiableMap(result);
}
}
public class MutablePoint { /* Listing 4.5 */ }
最佳答案
这个问题已经被回答过几次了,但是我觉得其中很多回答是不够的。看:
you want to ensure that it is seen correctly by all of the other thread (sic)
final
字段将保留其期望值(请注意初始化和初始化之间的区别)出版物)。该代码示例还同步了对
locations
字段的访问,以确保对
final
字段的更新是线程安全的。
VolatileCachedFactorizer
)。请注意,即使
OneValueCache
是不可变的,它也存储在
volatile
字段中。为了说明FAQ语句,如果没有
VolatileCachedFactorizer
,
volatile
将无法正常工作。 “同步”是指使用
volatile
字段,以确保对其进行的更新对其他线程可见。
volatile
。在这种情况下,
CachedFactorizer
将不起作用。考虑一下:如果一个线程设置了一个新的缓存值,而另一个线程试图读取该值并且该字段不是
volatile
,该怎么办?读者可能看不到更新的
OneValueCache
。但是,请回想一下Goetz引用了不可变对象(immutable对象)的
状态,如果读者线程碰巧看到存储在
OneValueCache
上的
cache
的最新实例,那么该实例的状态将是可见的并已正确构建。
cache
的更新,但如果是不可更改的,则不可能丢失
OneValueCache
的状态(如果已读取)。我建议阅读随附的文字,其中指出“可变引用用于确保及时可见。”
FinalWrapper
for thread safety。请注意,FinalWrapper实际上是不可变的(取决于单例是否可变),并且
helperWrapper
字段实际上是非 volatile 的。回顾第二个FAQ语句,访问该引用需要同步,那么这个“正确”的实现怎么可能是正确的呢?
helperWrapper
的最新值。如果
helperWrapper
保留的值不为null,那就太好了!我们的第一个JCIP语句保证
FinalWrapper
的状态是一致的,并且我们有一个完全初始化的
Foo
单例,可以很容易地返回它。如果该值实际上为null,则有两种可能性:首先,有可能是第一个调用,并且尚未初始化。其次,这可能只是一个过时的值(value)。
FinalWrapper
并进行同步发布。
helperWrapper
字段,并且当前线程尚未看到它。通过进入同步块(synchronized block),将与之前的写入建立先发生后关系,因为根据我们的第一种情况,真正的未初始化
helperWrapper
将由相同的锁初始化。因此,一旦方法进入同步上下文并获得最新的非空值,它可以通过重新读取来恢复。
关于multithreading - 对Java中的安全发布和可见性(尤其是不可变对象(immutable对象))感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47957697/
为什么禁用类型像 type t = A of int | B of string * mutable int 虽然允许此类类型: type t = A of int | B of string * i
我正在寻找一种类似结构的数据结构,我可以从中创建多个实例并具有某种类型提示而不是不可变的。 所以我有这样的东西: class ConnectionConfig(NamedTuple): nam
我需要转到引用的结构: class SearchKnot { var isWord : Bool = false var text : String = "" var to
如sec 10.4.3中所述 当控制进入执行时,执行以下步骤 功能对象F(调用者)中包含的功能代码的上下文 提供thisArg,而调用方提供argumentsList: 如
i make a game that start display Activity indicator And activity indicator bottom display UiLable wi
编辑:我在这里不断获得支持。只是为了记录,我认为这不再重要。自从我发布它以来我就不再需要它了。 我想在 Scala 中执行以下操作... def save(srcPath: String, destP
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
如果您在Kotlin中访问List类型的Java值,则将获得(Mutable)List!类型。 例如。: Java代码: public class Example { public stati
我编写了 str 类(内置)的以下扩展,以便执行以下操作:假设我有字符串 "Ciao" ,通过做"Ciao" - "a"我想要的结果是字符串 "Cio" 。这是执行此操作的代码,并且运行良好: cla
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
我正在为我的公司设计一个数据库来管理商业贷款。每笔贷款都可以有担保人,可以是个人或公司,在借款业务失败时作为财务支持。 我有 3 个表:Loan、Person 和 Company,它们存储明显的信息。
我使用二进制序列化从 C# 类中保存 F# 记录。一切正常: F#: type GameState = { LevelStatus : LevelStatus
import javax.swing.JOptionPane; public class HW { public static void main(String[] args) { Strin
使用 flatbuffer mutable 有多少性能损失? 是否“正确”使用 FlatBuffers 来拥有一个应该可编辑的对象/结构(即游戏状态) 在我的示例中,我现在有以下类: class Ga
std::function create_function (args...) { int x = initial_value (args...); return [x] () mut
我需要在 for 循环中找到用户输入的字符。我通常会这样做 如果(句子[i] == 'e') 但是因为在这里,'e' 将是一个单字母字符变量,我不知道如何获取要比较的值。我不能只输入 if (sent
我有一个这样的算法: let seed: Foo = ... let mut stack: Vec = Vec::new(); stack.push(&seed); while let Some(ne
这个问题可能看起来非常基础,但我很难弄清楚如何做。我有一个整数,我需要使用 for 循环来循环整数次。 首先,我尝试了—— fn main() { let number = 10; // An
如果我有以下结构: struct MyStruct { tuple: (i32, i32) }; 以及以下函数: // This will not compile fn function(&mut s
我希望在每个 session 的基础上指定列的默认值。下面的脚本不起作用,但描述了我想如何使用它。我目前使用的是 MySQL 5.5.28,但如果需要可以升级。 CREATE TABLE my_tbl
我是一名优秀的程序员,十分优秀!