public Holder holder;
public void initialize() {
holder = new Holder(42);
}
《Java并发编程实战》上说这种不正确的发布会导致其他线程看到尚未创建完成的对象。我想请教这种情况发生的原因。是因为未使用同步产生的指令重排序吗,导致holder提前获得了未初始化的holder对象引用吗?如果是,那我是否可以使用volatile关键字来解决这个指令重排序的问题,因为这里可以看作只有写入的线程,其他都是读线程。
我希望大佬们能够详细为我解释一下。
从提供的代码来看holder = new Holder(42);
这个语句,可以被分解为:
1.为 holder
分配内存
2.初始化 Holder
对象的字段(42)
3.将对象引用 holder
指向已构造的 Holder
实例
上述存在的问题:第3步可能会在第2步之前完成,这就导致了其他线程看到了这个对象的引用,存在空指针问题。
所以,指令重排可能导致其他线程在 holder
引用被正确初始化之前就已经看到这个对象的引用
使用 volatile
后,会存在内存屏障,所以上述3个步骤会按顺序执行,就不会被打乱。
问题内容: 这个问题基本上是不言而喻的。我无法找到用于数组的API(除了此Arrays之外,但这仅定义了一堆用于处理实际数组的静态辅助函数)。如果没有它的类,这似乎表明数组不能是。 然而,事实上,一个阵列具有公共领域,如和方法,它可以调用像和似乎暗示(强烈)相反完整。 对原始数组的奇数表示和行为有何解释? 作为说明,我现在尝试在数组的方法上使用“开放实现” Eclipse功能,希望我能够查看定义此
问题内容: 我知道当我初始化一个char数组时: 要么 为什么不喜欢 初始化数组: 为什么它们不同?它是Java哲学的本质之一还是其背后的某些原因? 问题答案: 如果您曾经使用过 C ,那么答案就非常简单。在 C语言中 ,创建数组的方式是在堆栈上分配一个足以容纳元素数量的静态内存长度,并使用指针指向第一个元素-或堆上动态内存长度,然后用指针指向第一个元素。 在 C ++中 ,第二个版本已更改为
问题内容: 我在用Java工作。 我通常会这样设置一些对象: 问题是:在此示例中是否等于,按原样我可以假定对未初始化的对象进行空检查将是准确的? 问题答案: 正确,未显式初始化的引用类型的静态成员和实例成员都由Java 设置为。相同的规则适用于数组成员。 根据Java语言规范的第4.12.5节: 变量的初始值 程序中的每个变量在使用值之前都必须具有一个值: 每个类变量,实例变量或数组组件在创建时均
问题内容: 我已经搜索了很多,但找不到特定的解决方案。关于stackoverflow也有一些问题,但我无法找到满意的答案,所以我再次询问。 我在java中有一个如下类。 我知道如何在Java中使用线程。 现在我想同时执行这两个操作。为此,我创建了两个线程类,一个在运行中执行addString()逻辑,另一个在执行deleteString()逻辑中。我在每个线程的构造函数中传递mylist,但是在对
类OneValueCache是不可变的。但是我们可以更改变量缓存的引用。 但我不能理解为什么VolateCachedFactorizer类是线程安全的。 对于两个线程(线程A和线程B),如果线程A和线程B同时到达,那么两个线程A和B都将尝试创建OnEvalueCache。然后线程A到达而线程B同时到达。然后线程A将创建一个,它覆盖threadB创建的值(OneValueChange是不可变的,但是
问题内容: 我正在使用静态代码块来初始化我拥有的注册表中的某些控制器。因此,我的问题是,我可以保证在首次加载该类时,该静态代码块仅被绝对调用一次吗?我知道我不能保证何时将调用此代码块,我猜是在Classloader首次加载时。我意识到我可以在静态代码块中的类上进行同步,但是我猜这实际上是怎么回事? 简单的代码示例将是; 还是我应该这样做? 问题答案: 是的,Java静态初始化器是线程安全的(使用第
问题内容: 我有我在create()方法中创建的对象编号列表,我想访问它,以便可以在question()方法中使用它。 还有可能我可能错过的另一种方法吗?我搞砸了吗?如果没有,我应该如何获得与以下相同的功能? 问题答案: 有趣的是,列出的两个答案都忽略了发问者正在使用静态方法的事实。因此,除非类类或成员变量也被声明为静态或静态引用,否则该方法将无法访问任何类或成员变量。这个例子: 会起作用的,但是
我想用Java 8-9启动线程,使用异步模式,这些是我的类和我的线程: 我有三根线。我的类包含单个方法 按以下方式设置我的%s: 正在创建线程: 最后,我的问题是我如何使用异步模式启动这三个线程。