我已经阅读了很多,但没有找到明确的答案.
我有一个看起来像这样的课程:
public class Foo() {
private static final HashMap<String, HashMap> sharedData;
private final HashMap myRefOfInnerHashMap;
static {
// time-consuming initialization of sharedData
final HashMap<String, String> innerMap = new HashMap<String, String>;
innerMap.put...
innerMap.put...
...a
sharedData.put(someKey, java.util.Collections.unmodifiableMap(innerMap));
}
public Foo(String key) {
this.myRefOfInnerHashMap = sharedData.get(key);
}
public void doSomethingUseful() {
// iterate over copy
for (Map.Entry<String, String> entry : this.myRefOfInnerHashMap.entrySet()) {
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道从Foo实例访问sharedData是否是线程安全的(如构造函数和doSomethingUseful()中所示).Foo的许多实例将在多线程环境中创建.
我的意图是sharedData在静态初始化程序中初始化,之后不再修改(只读).
我读过的是不可变对象本质上是线程安全的.但我只是在实例变量的上下文中看到了这一点.不可变的静态变量是否安全?
我找到的另一个构造是ConcurrentHashMap.我可以创建ConcurrentHashMap类型的sharedData但是它包含的HashMaps也必须是ConcurrentHashMap类型的?基本上..
private static final ConcurrentHashMap<String, HashMap> sharedData;
Run Code Online (Sandbox Code Playgroud)
要么
private static final ConcurrentHashMap<String, ConcurrentHashMap> …Run Code Online (Sandbox Code Playgroud) 我看了这个问题,如何做双检锁:
// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我的目标是在没有volatile属性的情况下延迟加载字段(而不是单例).初始化后,字段对象永远不会更改.
经过一些测试我的最终方法:
private FieldType field;
FieldType getField() {
if (field == null) {
synchronized(this) {
if (field == null)
field = Publisher.publish(computeFieldValue());
} …Run Code Online (Sandbox Code Playgroud) java multithreading final java-memory-model double-checked-locking
我在一本书中读过这句话,但我不理解:
静态和最终的字段只有一个无法更改的存储空间.
有谁可以帮我解释一下?
有没有办法让变量可以只分配一次?像这样
interface IFACE{
a: number;
final b: number;
}
IFACEConstructor (a: number): IFACE {
return {a: a, b: 1}
}
test = IFACEConstructor(2);
test.a = 5 //OK
test.b = 2 //Error
Run Code Online (Sandbox Code Playgroud) 为什么C#不允许在同一行上使用const和static?在Java中,您必须将字段声明为"static"和"final"以充当常量.为什么C#不允许你将const声明为final?
我进一步区分在Java中,每个接口都是公共的和抽象的,无论是否显式声明.const本质上不是有效的静态吗?为什么C#对此不以为然?
这个问题来自我的Java test学习指南.有人能解释一下为什么会这样吗?
这段代码打印出5号而不是12号.你能解释一下原因吗?你能解释为什么如果第二个变量也是12,它会打印出来final,如果它们都不是,那么它会打印出来final吗?
public class Question26 {
public static void main(String[] args) {
System.out.println(Q26.q26.ans);
}
}
class Q26 {
public static Q26 q26 = new Q26();
public int ans;
private static final int var1 = 5;
private static int var2 = 7;
public Q26() {
ans = var1 + var2;
}
}
Run Code Online (Sandbox Code Playgroud) 我的最终变量有问题.任何帮助将不胜感激.
这是我的第一个工作正常的代码
final int i = 90;
byte b = i ;
System.out.println(i);
Run Code Online (Sandbox Code Playgroud)
这是我的第二个代码,它表示可能会损失精度.这有什么不对?
final int i;
i = 90;
byte b = i ;
System.out.println(i);
Run Code Online (Sandbox Code Playgroud) 我刚刚开始使用Hibernate,到目前为止我看到的所有示例看起来都非常像Hibernate文档中的教程:
package org.hibernate.tutorial.domain;
import java.util.Date;
public class Event {
private Long id;
private String title;
private Date date;
public Event() {}
/* Accessor methods... */
}
Run Code Online (Sandbox Code Playgroud)
具体来说:没有任何字段被声明为final,并且必须有一个无参数构造函数,以便Hibernate框架可以实例化该类并设置其字段.
但事情就是这样 - 我真的不喜欢每当我能避免它时就以任何方式使我的类变得可变(Java实践:不可变对象为此做出了相当强烈的论据).那么,即使我要声明每个字段的"最终",有没有办法让Hibernate工作?
我知道Hibernate使用Reflection来实例化它的类,因此需要能够调用某种构造函数,而不会冒险选择错误的构造函数或将错误的值传递给它的一个参数,所以它可能更安全调用no-arg构造函数并一次设置一个字段.但是,是否应该可以向Hibernate提供必要的信息,以便它可以安全地实例化不可变对象?
public class Event {
private final Long id;
private final String title;
private final Date date;
public Event(@SetsProperty("id") Long id,
@SetsProperty("title") String title,
@SetsProperty("date") Date date) {
this.id = id;
this.title = title;
this.date = new Date(date.getTime());
}
/* Accessor methods... */
} …Run Code Online (Sandbox Code Playgroud) 我一直在使用PMD帮助发现我的Java代码中的潜在问题,我一直在寻找它的建议,分为有用的,特殊的和"WTF ?!".
它一直告诉我要做的事情之一就是将final关键字用于字面上我可以附加的每个变量,包括输入参数.对于实际的常数,这似乎是明智的,但对于其他东西,它只是让我感到奇怪,甚至可能适得其反.
挂final在每个变量声明上是否有具体的优点/缺点?
如果我有一个在线程之间共享的对象,在我看来每个字段应该是final或者volatile,具有以下推理:
如果应该更改字段(指向另一个对象,更新原始值),那么该字段应该是volatile所有其他线程对新值进行操作.仅仅访问所述字段的方法的同步是不够的,因为它们可能返回缓存的值.
如果该领域永远不会改变,那就去做吧final.
但是,我找不到任何关于此的内容,所以我想知道这个逻辑是否有缺陷还是太明显?
当然编辑而不是易失性可能使用final AtomicReference或类似.
编辑,例如,请参阅get getter方法是Java中volatile的替代方法吗?
编辑以避免混淆:这个问题是关于缓存失效!如果两个线程对同一个对象进行操作,则可以缓存对象的字段(每个线程),如果它们未声明为volatile.如何保证缓存无效?
最后的编辑感谢@Peter Lawrey,他指出了JLS§17(Java内存模型).据我所知,它表明同步在操作之间建立了先发生关系,因此如果那些更新"发生在之前",则线程会看到来自另一个线程的更新,例如,如果非易失性字段的getter和setter是synchronized.