给出以下代码:
public class FooBar {
public static volatile ConcurrentHashMap myConfigData = new ConcurrentHashMap();
}
public class UpdaterThread implements Runnable {
run {
//Query the Data from the DB and Update the FooBar config Data
FooBar.myConfigData = ConfigDataDAO.getLatestConfigFromDB();
}
}
Thread-Class将定期更新myConfigData Membervariable(每5分钟通过一个Executor)。 myConfigData的设置是在“外部”线程threadafe(原子)中,还是我必须将每个Read和Write操作同步到myConfigData变量?
编辑:问题不在于ConcurrentHashMap是线程安全的(它是根据javadoc)而是在myConfigData Member变量中设置ConcurrentHashMap本身。这个变量可能被几个线程“一次”读取和写入,所以问题是该设置是否是原子的。我认为这可以推广为“Java引用变量的设置是否为原子?”。
(我也使它变得不稳定。这是一个不同的问题,与原子性无关 - 我的问题 - 而是“其他线程中的可见性”和之前发生的关系。)
答案 0 :(得分:14)
更换参考资料是安全的。见Java language Specification:
当线程使用变量的值时,它获得的值实际上是由该线程或某个其他线程存储到变量中的值。即使程序不包含正确同步的代码,也是如此。例如,如果两个线程将对不同对象的引用存储到同一引用值中,则该变量随后将包含对一个对象或另一个对象的引用,而不是对某个其他对象的引用或损坏的引用值。 (长值和双值有一个特殊例外;见§17.4。)
答案 1 :(得分:2)
volatile
保证原子性,可见性并充当“内存障碍”(google for it,如果你想知道这意味着什么) - 至少从Java 5开始。
因此它完全符合您的要求。
答案 2 :(得分:0)
ConcurrentHashMp是:
一个哈希表,支持检索的完全并发和可更新的预期并发性。该类遵循与Hashtable相同的功能规范,并包括与Hashtable的每个方法相对应的方法版本。但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。在依赖于线程安全但不依赖于其同步细节的程序中,此类可与Hashtable完全互操作。
javadocs说它是线程安全的。
看起来像设置配置的大量工作和CPU周期。真的是这种动态吗?或者你每个月换一次,当你这样做时只需要服务反弹?
答案 3 :(得分:0)
如果通过更新意味着覆盖ConcurrentHashMap中的条目:
FooBar.myConfigData.put(somekey, somevalue);
然后它绝对是线程安全的,正如duffymo所说。
如果要使用新值覆盖myConfigData变量:
FooBar.myConfigData = new ConcurrentHashMap();
它也是线程安全的,因为您已正确将变量标记为volatile。 volatile关键字意味着多个线程可以安全且原子地访问同一个变量。
编辑:问题不是ConcurrentHashMap是线程安全的(它是根据javadoc)而是在myConfigData Member变量中设置ConcurrentHashMap本身。这个变量可能被几个线程“一次”读取和写入,所以问题是,如果设置是原子的或不是。我认为这可以概括,是否设置Java Reference变量原子。
(我也使它变得不稳定。这是一个不同的问题,与原子性无关(我的问题),而是“在其他线程中的可见性”以及在关系之前发生的事情。)
实际上'volatile'对于原子性来说是,没有什么会影响可见性,任何线程都可以看到公共变量。
答案 4 :(得分:0)
如果你不确定,你总是可以使用AtomicReference。
虽然我认为在你的情况下,挥发性就足够了。