java - How to make writes to array visible to other Threads -
i have input array of basic type int, process array using multiple threads , store results in output array of same type , size. following code correct in terms of memory visibility?
import java.util.concurrent.countdownlatch; import java.util.concurrent.executionexception; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.timeunit; public class arraysynchronization2 { final int width = 100; final int height = 100; final int[][] img = new int[width][height]; volatile int[][] avg = new int[width][height]; public static void main(string[] args) throws interruptedexception, executionexception { new arraysynchronization2().dojob();; } private void dojob() throws interruptedexception, executionexception { final int threadno = 8; executorservice pool = executors.newfixedthreadpool(threadno); final countdownlatch countdownlatch = new countdownlatch(width - 2); (int x = 1; x < width - 1; x++) { final int col = x; pool.execute(new runnable() { public void run() { (int y = 0; y < height; y++) { avg[col][y] = (img[col - 1][y] + img[col][y] + img[col + 1][y]) / 3; } // how can make writes data in avg[][] visible other threads? ok? avg = avg; countdownlatch.countdown(); }; }); } try { // make memory visibility guarantees? countdownlatch.await(); } catch (interruptedexception e) { e.printstacktrace(); } // can read avg here, results correct? (int x = 0; x < width; x++) { (int y = 0; y < height; y++) { system.out.println(avg[x][y]); } } pool.shutdown(); pool.awaittermination(long.max_value, timeunit.days); // know tasks completed , results synchronized (after thread death), if plan reuse pool? } }
i not want synchronize on countdownlatch. know how make writes output array visible other threads. let imagine have array (eg. image) process, in multiple separate tasks process chunks of input array output array, there no inter-dependencies between writes output. after computations complete, have results in output array ready read. how achieve such behaviour? know achievable using submit , future.get() instead of execute, i'd know how implement such low-level mechanism? please refer questions raised in comments near code.
hm, wondering if need latch. array reserved block in memory, every cell being dedicated memory address. (btw. marking volatile mark reference array volatile, not cells of array, see here). need coordinate access cells if multiple threads write-access same cell.
question is, doing this? or aim should be: avoid coordinating access if possible, because comes @ cost.
in algorithm, operate on rows, why not parallelize on rows, each thread reads & calculates values of row-segement of entire array , ignore other rows?
i.e.
- thread-0 -> rows 0, 8, 15, ...
- thread-1 -> rows 1, 9, 16, ...
- ...
basically (haven't tested):
for (int n = 0; n < threadno; n++) { //each n relates thread pool.execute(new runnable() { public void run() { (int row = n; row < height; row += threadno) { //proceed next row thread (int col = 1; col < width-1; col++) { avg[col][row] = (img[col - 1][row] + img[col][row] + img[col + 1][row]) / 3; } } }; }); }
so can operate on entire array without having synchronize @ all. putting loop print out result after shutting down pool ensure calculate-threads have finished, , thread has wait main thread.
an alternative approach create avg-array of size 100/threadno
each thread each thread write-operate on it's on array , merge arrays afterwards system.arraycopy()
1 array.
if intend reuse pool, should use submit
instead of execute , call get()
on futures submit.
set<future> futures = new hashset<>(); for(int n = 0; ...) { futures.add(pool.submit(new runnable() {...})); } for(future f : futures) { f.get(); //blocks until task completed }
in case want read intermediate states of array can either read directly, if inconsistent data on single cells acceptable, or use atomicintegerarray, nicolas filotto suggested.
-- edit --
after edit using width latch instead of original thread number , discussion i'd add few words.
as @jameslarge pointed out, it's how establish "happens-before" relationship, or how guarantee, operation (i.e. write) happens before operation b (i.e. read). therefore access between 2 threads needs coordinated. there several options
- volatile keyword - doesn't work on arrays marks reference , not values being volatile
- synchronization - pessimistic locking (
synchronized
modifier or statement) - cas - optimistic locking, used quite few concurrent implementations
however every syncpoint (pessimistic or optimistic) establishes happens-before relationship. 1 choose, depends on requirement.
what achieve coordination between read operation of main thread , write operations of worker threads. how implement, , requirements. countdownlatch counting down total number of jobs 1 way (btw., latch uses state property volatile int
). cyclicbarrier may construct worth consider, if you'd read consistent intermediate states. or future.get(), or... boils down worker thread having signal they're done writingso reader thread can start reading.
however aware of using sleep instead of synchronization. sleep not establish happens before relationship, , using sleep synchronization typical concurrency bug pattern. i.e. in worst case, sleep executed before of work has been done.
Comments
Post a Comment