这段代码是线程安全的吗?

Kut*_*ach 6 java concurrency multithreading concurrenthashmap

我想处理客户端请求流.每个请求都有其特殊类型.首先,我需要为该类型初始化一些数据,然后我可以开始处理请求.当客户端类型第一次出现时,我只是初始化相应的数据.在此之后,使用该数据处理该类型的所有以下请求.

我需要以线程安全的方式执行此操作.

这是我写的代码.它是线程安全的吗?

public class Test {

    private static Map<Integer, Object> clientTypesInitiated = new ConcurrentHashMap<Integer, Object>();

    /* to process client request we need to 
    create corresponding client type data.
    on the first signal we create that data, 
    on the second - we process the request*/

    void onClientRequestReceived(int clientTypeIndex) {
        if (clientTypesInitiated.put(clientTypeIndex, "") == null) {
            //new client type index arrived, this type was never processed
            //process data for that client type and put it into the map of types
            Object clientTypeData = createClientTypeData(clientTypeIndex);
            clientTypesInitiated.put(clientTypeIndex, clientTypeData);
        } else {
            //already existing index - we already have results and we can use them
            processClientUsingClientTypeData(clientTypesInitiated.get(clientTypeIndex));
        }
    }

    Object createClientTypeData(int clientIndex) {return new Object();}

    void processClientUsingClientTypeData(Object clientTypeData) {}
}
Run Code Online (Sandbox Code Playgroud)

一方面,ConcurrentHashMap不能为同一个A生成map.put(A,B)== null两次.另一方面,赋值和比较运算不是线程安全的.

那么这段代码还可以吗?如果没有,我该如何解决?

更新:我接受了Martin Serrano的答案,因为他的代码是线程安全的,并且不容易出现双重初始化问题.但我想指出,我没有找到任何与我的版本相关的问题,在下面发布作为答案,我的版本不需要同步.

Mar*_*ano 2

这段代码不是线程安全的,因为

//already existing index - we already have results and we can use them
processClientUsingClientTypeData(clientTypesInitiated.get(clientTypeIndex));
Run Code Online (Sandbox Code Playgroud)

有机会获得您临时插入 put 检查中的“”值。

这段代码可以这样实现线程安全:

public class Test {

    private static Map<Integer, Object> clientTypesInitiated = new ConcurrentHashMap<Integer, Object>();

    /* to process client request we need to 
       create corresponding client type data.
       on the first signal we create that data, 
       on the second - we process the request*/

void onClientRequestReceived(int clientTypeIndex) {
    Object clientTypeData = clientTypesInitiated.get(clientTypeIndex);
    if (clientTypeData == null) {
        synchronized (clientTypesInitiated) {
          clientTypeData = clientTypesInitiated.get(clientTypeIndex);
          if (clientTypeData == null) {
              //new client type index arrived, this type was never processed
              //process data for that client type and put it into the map of types
              clientTypeData = createClientTypeData(clientTypeIndex);
              clientTypesInitiated.put(clientTypeIndex, clientTypeData);
          }
        }
    }
    processClientUsingClientTypeData(clientTypeData);
}

Object createClientTypeData(int clientIndex) {return new Object();}

void processClientUsingClientTypeData(Object clientTypeData) {}
Run Code Online (Sandbox Code Playgroud)

}