我已经阅读了很多,但没有找到明确的答案.
我有一个看起来像这样的课程:
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) 我的J2EE webapp启动时,我一次填充一个集合.然后,几个线程可以同时访问它,但只能读取它.
我知道使用同步集合对于并行写入是强制性的,但是我仍然需要它来进行并行读取吗?
我希望这不是一个愚蠢的问题......
我的代码中的代码类似于以下代码:
public class ConfigStore {
public static class Config {
public final String setting1;
public final String setting2;
public final String setting3;
public Config(String setting1, String setting2, String setting3) {
this.setting1 = setting1;
this.setting2 = setting2;
this.setting3 = setting3;
}
}
private volatile HashMap<String, Config> store = new HashMap<String, Config>();
public void swapConfigs(HashMap<String, Config> newConfigs) {
this.store = newConfigs;
}
public Config getConfig(String name) {
return this.store.get(name);
}
}
Run Code Online (Sandbox Code Playgroud)
处理请求时,每个线程将使用getConfig()函数从存储中请求使用配置.但是,定期(最有可能每隔几天),使用swapConfigs()函数更新和交换配置.调用swapConfigs()的代码不会保留对它传入的Map的引用,因为它只是解析配置文件的结果.
volatile商店实例变量仍然需要关键字吗?volatile关键字带来任何潜在的性能瓶颈,我应该知道的或可避免因为读取的速度大大超过写入的速度?非常感谢,
一个线程在它自己的构造函数中调用this.start()是否合法?如果是这样,这会导致什么样的潜在问题?我知道对象不会完全初始化,直到构造函数运行完成,但除此之外还有其他问题吗?
我正在尝试创建一个Map带有int值并通过多个线程增加它们.两个或多个线程可能会增加相同的密钥.
ConcurrentHashMap 文档对我来说非常不清楚,因为它表明:
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove)
我想知道以下代码使用ConcurrentHashMap是否正常:
myMap.put(X, myMap.get(X) + 1);
如果没有,我该怎么办呢?
HashMap我的程序中有一个由多个线程访问,偶尔由一个线程设置.
例如:
Map<String, String> myMap = new HashMap<String, String>();
Run Code Online (Sandbox Code Playgroud)
这可以通过多个线程访问.每小时一次,一个线程调用:
myMap = myRefreshedVersionOfTheMap;
Run Code Online (Sandbox Code Playgroud)
所以我的问题是这是否是线程安全的.如果两个映射始终都有密钥"importantKey",那么读取线程是否可以在"importantKey"不存在时访问映射?
编辑:
感谢答案,我意识到这个问题实际上是独立的HashMap.这是一个关于对象引用分配的问题.
java multithreading reference thread-safety java-memory-model
根据JCP(16.2.2.安全出版物):
这种情况发生之前 - 保证实际上是一种比安全出版物更强的可见性和排序承诺.当X安全地从A发布到B时,安全发布保证了X的状态的可见性,但不保证A可能触及的其他变量的状态.但是如果A在队列中放置X,那么在B从该队列中取出X之前,不仅B在A离开它的状态下看到X(假设X后来没有被A或其他任何人修改过),但B看到A在切换之前所做的一切(再次,同样需要注意)
我想知道什么时候安全发布可以没有发生 - 也就是说没有使用volatile/atomics或同步(或通过使用任何内部列出的AQS之类的框架)?
一种情况是不可变对象中的最终字段,您可以将其发布为没有任何其他步骤.
还有其他案件吗?
UPD:重新阅读3.5.3.安全发布惯用语,另一种情况 - "从静态初始化程序初始化对象引用".现在看来这些都是选择.
嗨
下面的课程线程安全吗?
class ImmutablePossiblyThreadsafeClass<K, V> {
private final Map<K, V> map;
public ImmutablePossiblyThreadsafeClass(final Map<K, V> map) {
this.map = new HashMap<K, V>();
for (Entry<K, V> entry : map.entrySet()) {
this.map.put(entry.getKey(), entry.getValue());
}
}
public V get(K key) {
return this.map.get(key);
}
}
Run Code Online (Sandbox Code Playgroud) java ×8
concurrency ×4
final ×1
hashmap ×1
immutability ×1
map ×1
reference ×1
static ×1
visibility ×1
volatile ×1