Antoine
Antoine

Reputation: 946

Thread safety in Java hashMap

Is the following code thread safe?

HashMap<Integer, HashMap<Integer, Double>> hMap = new HashMap<Integer, HashMap<Integer, Double>>();
ExecutorService executor = Executors.newFixedThreadPool(threads);
// the next line is new
ArrayList<Future<Double>> results = new ArrayList<Future<Double>>();
for (Integer i = 0; i < iBound; i++) {
    hMap.put(i, new HashMap<Integer, Double>());
    for (Integer j = 0; j < jBound; j++) {
        SomeCallable task = new SomeCallable(i, j);
        Future<Double> result = executor.submit(task);
        results.add(result);  // hMap.get(i).put(j, result.get());
    }
}
executor.shutdown();
executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);

// the next lines are new
int index = 0;
for (Integer i = 0; i < iBound; i++) {
    hMap.put(i, new HashMap<Integer, Double>());
    for (int j = 0; j < jBound; j++) {
        hMap.get(i).put(j, results.get(index).get());
        index++;
    }
}

I would say yes, since different threads work with different keys in the hash maps. I have tested this and compared hMap that is obtained in the multi-thread scenario to the hMap that is obtained in the following way:

HashMap<Integer, HashMap<Integer, Double>> hMap = new HashMap<Integer, HashMap<Integer, Double>>();
for (Integer i = 0; i < iBound; i++) {
    hMap.put(i, new HashMap<Integer, Double>());
    for (Integer j = 0; j < jBound; j++) {
        SomeCallable task = new SomeCallable(i, j);
        hMap.get(i).put(j, task.call());
    }
}

I varied the number of threads from 2 to 20 and was changing the time complexity ofSomeCallable.call. The bounds iBound and jBound were set to 500.

There were no differences between hMaps, but I want to be sure.

Upvotes: 1

Views: 201

Answers (2)

GPI
GPI

Reputation: 9348

As long as SomeCallable does not internally access the hMap instance variable (and is inherently thread safe itself), then this code is safe. We can safely assume that because all manipulations done to hMap come from the same thread (each and every put / get come from the thread that performs the loop).

On the other hand, there is no real point in executing all this in a threaded manner if after submitting each task, one immediately waits for this task's completion. You might as well use your second code sample, because in practice, your first only ever uses one thread at a time.

And maybe if you actually start using threading in a more "usefull" way, then you HashMap usage may become unsafe.

Upvotes: 4

Dan
Dan

Reputation: 1033

I'd recommend using a ConcurrentHashMap instead. All protections are in place by default.

Upvotes: 1

Related Questions