Is it required to synchronize write access to an array in Java if each thread writes to a separate cell space?
EDIT: Specifically, the array is eith
You can do what you are asking, updating what each index holds, but you are not guaranteed that other threads reading the data in the indexes are seeing current data.
There is a keyword in Java called volatile
that marks instance and class variables so that they JVM knows these values are expected to change and to not do any read cache optimization because the reading threads may get stale data. Since you can't mark array index contents volatile
other readers can get stale data.
Using raw Arrays
in Java is only good practice in very specific scenarios. Yours might be one of those cases, but I can't tell from the question, therefore I suggest you look at java.util.concurrent specifically at CopyOnWriteArrayList and CopyOnWriteArraySet if you don't want duplicates.
These are part of the standard library for a reason now, and if you are doing heavy threading and data sharing you should be as intimately familiar with java.util.concurrent
as possible.
Don't write directly to a shared resource. Your gonna make the multi thread program perform worse than its single thread counter part. Trashing effect in Cache as Cache is fetched and invalidated in blocks. Do look at this talk if you want to know more. Use volatile and Synchronize its better than using nothing but still slow.
https://www.youtube.com/watch?v=VCattsfHR4o
Not a simple yes or no issue. Some things to consider:
long
or double
values is not safe without synchronizationdouble
or long
, there is the possibility of another threads not being able to see changed values immediately because of caching (resulting in stale reads)Are the same threads also reading the value. If so then you are ok. If not then you need to worry about whether other threads see the most recent values. This is usually taken care of through the key work volatile or through atomics variables.
For example if you have an int [] intArray with three elements.
thread 1 updates intArray[0]=<new value>
thread 2 updates intArray[1]=<new value>
thread 3 updates intArray[2]=<new value>
if these threads also are used to read the values then you are ok but if a new thread --> thread 4 attempts to read the values then there is no guarantee that it will see the latest assignment.
you'll be ok if you use AtomicIntegerArray, AtomicLongArray, or AtomicReferenceArray
No, synchronization is not needed.
It is defined in JLS §17.6 Word Tearing:
One implementation consideration for Java virtual machines is that every field and array element is considered distinct; updates to one field or element must not interact with reads or updates of any other field or element. In particular, two threads that update adjacent elements of a byte array separately must not interfere or interact and do not need synchronization to ensure sequential consistency.
I was about to add a Question with this topic. I made a test that force contention while accessing an array. Both controlling coordinated access or with a non-synchronized read-modify-write operation like index--.
When using index-- some counters are > 1 (all should be 1, otherwise the mutual exclusion broke)
public class App {
static int threads = 1000;
static int maxIndex = 1000;
public static void main(String[] args)
{
try {
testThreads();
} catch (InterruptedException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
return;
}
public static void testThreads() throws InterruptedException {
AtomicInteger[] ids = new AtomicInteger[maxIndex];
for (int i = 0; i < maxIndex; i++) {
ids[i] = new AtomicInteger(0);
}
Executor exec = Executors.newFixedThreadPool(threads);
AtomicInteger index = new AtomicInteger(maxIndex);
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(threads);
for (int i = 0; i < threads; i++) {
exec.execute(new Runnable() {
@Override
public void run() {
try {
startGate.await();
try {
int i = maxIndex;
while (i > 0) {
/**
* Interchanging this lines force or avoid collisions.
*/
// i = --maxIndex;
i = index.decrementAndGet();
ids[i].incrementAndGet();
}
} catch(Exception ignored) {
System.out.println(ignored);
} finally {
endGate.countDown();
}
} catch (InterruptedException ignored) {
}
}
});
}
startGate.countDown();
endGate.await();
System.out.println(new ArrayList(Arrays.asList(ids)));
}
}