簡體   English   中英

對ConcurrentHashMap的值對象同時讀寫

[英]Simultaneous read write on value object of ConcurrentHashMap

我有一個ConcurrentHashMap:

ConcurrentHashMap<ID,Object> map;

在我的應用程序中,此映射為高讀和低寫

閱讀的工作方式如下:

public Response getObject() {
    Response response = createResponse();
    Object obj = map.get(ID);
    if (obj != null) {
        if (obj.getAttribute1() == some_value) {
            response.setAttr1(obj.getAttr1());
            response.setAttr2(obj.getAttr2());
        }
    }
    return response;
}

更新的工作方式如下:

public void updateObject(Object obj, int action) {
    if (action == ADD) {
        map.put(obj.getID(), obj);
    } else if (action == UPDATE) {
        object oldObj = map.get(obj.getID());
        if (oldObj != null) {
            map.put(obj.getID(), obj);
        }
    } else if (action == REMOVE) {
        object oldObj = map.get(obj.getID());
        if (oldObj != null) {
            map.remove(obj.getID());
        }
    }
}

現在我的問題是,ConcurrentHashMap是否足以在多線程環境中以線程安全的方式工作,還是必須通過ReadWrite鎖從外部鎖定Object或使用Object的克隆?

假設在從地圖讀取obj的情況下,ConcurrentHashMap將確保它將返回最新的寫入對象,但是當在讀取后立即由編寫器線程刪除/更新該對象時該怎么辦。Read對象(已從地圖刪除/更新)用於准備響應對象,其屬性用於做出某些決定。

而更新地圖的更好方法應該是什么?

為了使代碼相對於ConcurrentHashMap而言是線程安全的,您應該使用相應的compute方法(原子地執行):

public Response getObject() {
    Response response = createResponse();

    map.computeIfPresent(ID, (k, v) -> {
        if (v == some_value) {
            response.setAttr1(v.getAttr1());
            response.setAttr2(v.getAttr2());
        }

        return v;
    }

    return response;
}

和:

public void updateObject(Object obj, int action) {
    if (action == ADD) {
        map.put(obj.getID(), obj);
    } else if (action == UPDATE) {
        map.computeIfPresent(obj.getID(), (k, v) -> obj);
    } else if (action == REMOVE) {
        map.remove(obj.getID());
    }
}

如果只有一個編寫器,那么這是線程安全的。 否則,您執行的操作之間會出現競爭狀態。 因此,有些操作可以自動執行這些操作並簡化代碼。

public void updateObject(Object obj, int action) {
    switch (action) {
        case ADD:
            map.put(obj.getID(), obj);
            break;

        case UPDATE:
            map.computeIfPresent(obj.getID(), (k, v) -> obj);
            break;

        case REMOVE:
            map.remove(obj.getID());
            break;
    }
}

最有可能的是,您不需要特殊的更新操作,也可以將其put

我強烈建議不要將Object用作自定義類,而應使用新名稱。

讀取后立即由編寫器線程刪除/更新該對象該怎么辦

如果刪除該對象,則對持有該引用的另一個線程沒有影響。 如果通過在地圖中放置新對象來更新對象,則可以,但是,如果更新添加的對象,則可能不是線程安全的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM