Reputation: 434
I'm supernew to multi-threading, but I think I got the overall idea more or less. I'm trying to fill a matrix multi-threaded, but my code is clearly not thread-safe, I have duplicate columns in my matrix, which is not the case when the matrix is filled regularly. Below is an example block of code. Note that the reader is a Scanner object and someOperationOnText(someText) returns an int[100] object.
int[][] mat = new int[100][100];
ExecutorService threadPool = Executors.newFixedThreadPool(8);
for (int i = 0; i < 100; i++) {
Set<Integer>someText = new HashSet<>(reader.next());
int lineIndex = i;
threadPool.submit(() -> mat[lineIndex] = someOperationOnText(someText);
}
Do you see any reason why this is not thread-safe? I can't seem to get my head around it, since the reading is done outside the thread-pool, I didn't think it would be at risk.
Thanks a lot for any debugging tips! Grts
Upvotes: 0
Views: 190
Reputation: 719307
There is a happens-before between the submit
calls and the execution of the lambda by a thread in the executor's thread pool. (See javadoc: "Memory consistency effects"). So that means the lambda will see the correct values for someText
, mat
and lineIndex
.
The only thing that is not thread-safe about this is the (implied) code that uses the values in mat
in the main thread. Calling shutdown()
on the executor should be sufficient ... though the javadocs don't talk about the memory consistency effects of shutdown()
and awaitTermination()
.
(By my reading of the code for ThreadPoolExecutor
, the awaitTermination()
method provides a happens-before between the pool threads (after completion of all tasks) and the method's return. The happens-before is due the use of the executor's main lock to synchronize the pool shutdown. It is hard to see how they could implement shutdown correctly without this (or equivalent), so it is more than an "implementation artefact" ... IMO.)
Upvotes: 1
Reputation: 1108
Well, accessing elements in the matrix is a very fast operation, a computing is not.
I think making access to a matrix synchronized while computing can be concurrent is a right approach for you.
int[][] mat = new int[100][100];
Object lock = new Object();
ExecutorService threadPool = Executors.newFixedThreadPool(8);
for (int i = 0; i < 100; i++) {
Set<Integer> someText = new HashSet<>(reader.next());
int lineIndex = i;
threadPool.submit(() -> {
int result = someOperationOnText(someText);
synchronized (lock) {
mat[lineIndex] = result;
}
});
}
Upvotes: 0