Java 我们需要使ConcurrentHashMap易失性吗?
我们有一个共享的Java 我们需要使ConcurrentHashMap易失性吗?,java,concurrency,java.util.concurrent,Java,Concurrency,Java.util.concurrent,我们有一个共享的ConcurrentHashMap,它由两个线程读写 class Test { private ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>(); Object read() { return map.get(object); } void write(Object key, Object object) {
ConcurrentHashMap
,它由两个线程读写
class Test {
private ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
Object read() {
return map.get(object);
}
void write(Object key, Object object) {
map.put(key, object);
}
}
类测试{
私有ConcurrentHashMap=新ConcurrentHashMap();
对象读取(){
返回map.get(对象);
}
无效写入(对象键、对象){
放置(键、对象);
}
}
我们是否需要使映射具有易变性,以便读线程尽快看到一个线程的写操作
是否有可能一个线程中的put-to-map没有被另一个线程看到或很晚才被另一个线程看到
HashMap
的相同问题在语义读取和写入相应变量之前也会出现
字段可以声明为volatile,在这种情况下是Java内存模型
确保所有线程都能看到变量的一致值
(§17.4)
它与变量值引用的对象无关。您没有修改变量,因此不应该*有任何问题,除非(*)您没有安全地发布跨线程共享的Test
对象
假设您没有采取正确的预防措施,通过final
、volatile
或其他一些同步机制,JMM允许在对象的构造函数完全初始化之前提供对对象的引用。因此,您的一个线程可以在初始化map
字段之前尝试使用该字段(例如,它将看到null
)。从这个意义上讲,密码可能会被破解
是否有可能一个线程中的put-to-map没有被另一个线程看到或很晚才被另一个线程看到
这是不可能的,因为状态,ConcurrentHashMap
方法引入了适当的内存屏障
检索反映最近完成的更新的结果
手术一开始就进行。(更正式地说,是更新
给定键的操作在与任何
(非空)检索报告更新值的键
但是,
HashMap
不是一种线程安全类型。volatile
在这里也没有帮助,因为它控制变量的更改,而不是变量引用的对象。您需要外部同步来保护put
和get
对HashMap
的调用(如果可以final
然后这样做。如果您不能使其成为最终的
,那么您需要使其成为易失的
易失的
应用于字段分配,如果它不是最终的
,则有可能(至少根据JMM)一个线程对CHM字段的写入可能对另一个线程不可见。重申一下,这是ConcurrentHashMap
字段分配,不使用CHM
话虽如此,你真的应该让它成为最后的
我们是否需要使映射具有易变性,以便读线程尽快看到一个线程的写操作
如果您提到的写入是使用CHM本身的变异方法完成的(如put
或remove
),那么使字段不稳定不会产生任何效果。所有内存可见性保证都是在CHM内完成的
是否有可能一个线程中的put-to-map没有被另一个线程看到或很晚才被另一个线程看到?对于HashMap
,同样的问题
不适用于
ConcurrentHashMap
。如果同时使用普通HashMap
,请不要使用。请参阅:这里有两个子问题:对映射的引用的可见性和写入映射的值的可见性
//1. Provide access to the reference through a properly locked field
class Test {
ConcurrentHashMap map;
synchronized void init(ConcurrentHashMap map) {
this.map = map;
}
synchronized void read() {
map.get(object);
}
synchronized void write() {
map.put(key, object);
}
}
// or
class Test {
ReadWriteLock rwl = new ReentrantReadWriteLock();
ConcurrentHashMap map;
void init(ConcurrentHashMap map) {
rwl.writeLock().lock();
this.map = map;
rwl.writeLock().release();
}
void read() {
rwl.readLock().lock();
try {
map.get(object);
} finally {
rwl.readLock().release();
}
}
void write() {
rwl.writeLock().lock();
try {
map.put(key, object);
} finally {
rwl.writeLock().release();
}
}
}
// 3. Provide access to the reference via a volatile field
class Test {
volatile ConcurrentHashMap map; // or AtomicReference<ConcurrentHashMap> map = new AtomicReference();
void init(ConcurrentHashMap map) {
this.map = map;
}
void read() {
map.get(object);
}
void write() {
map.put(key, object);
}
}
// 4. Initialize the value as a final field
class Test {
final ConcurrentHashMap map;
Test(ConcurrentHashMap map) {
this.map = map;
}
void read() {
map.get(object);
}
void write() {
map.put(key, object);
}
}
//1.通过正确锁定的字段提供对引用的访问
课堂测试{
ConcurrentHashMap;
同步void init(ConcurrentHashMap映射){
this.map=map;
}
同步无效读取(){
map.get(对象);
}
同步无效写入(){
放置(键、对象);
}
}
//或
课堂测试{
ReadWriteLock rwl=新的ReentrantReadWriteLock();
ConcurrentHashMap;
void init(ConcurrentHashMap映射){
rwl.writeLock().lock();
this.map=map;
rwl.writeLock().release();
}
无效读取(){
rwl.readLock().lock();
试一试{
map.get(对象);
}最后{
rwl.readLock().release();
}
}
无效写入(){
rwl.writeLock().lock();
试一试{
放置(键、对象);
}最后{
rwl.writeLock().release();
}
}
}
//3.通过易失性字段提供对参考的访问
课堂测试{
volatile ConcurrentHashMap;//或AtomicReference map=new AtomicReference();
void init(ConcurrentHashMap映射){
this.map=map;
}
空隙率