Reputation: 135
Like the title, given 2 arrays int[] a
, int[] b
shared by two Threads each of which rearrange the elements of the two arrays in a way that each element of the first array is <=
of the corrispondent element of the second array a[i] <= b[i]
the output seems to be always correct without the needs of synchronization
public class MyClass {
int[] a = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
class MyThread extends Thread {
public void run() {
for (int i = 0; i < a.length; i++) {
if (a[i] > b[i]) {
int temp = b[i];
b[i] = a[i];
a[i] = temp;
}
}
}
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
MyThread t1 = myClass.new MyThread();
MyThread t2 = myClass.new MyThread();
t1.start();
t2.start();
while (t1.isAlive() | t2.isAlive()) {
System.out.println("waiting");
}
System.out.println(Arrays.toString(myClass.a));
System.out.println(Arrays.toString(myClass.b));
}
}
Here is the output i'm getting (on multiple runs) should i consider this only luck or is there somethig i'm missing?
a = [0, 1, 2, 3, 4, 4, 3, 2, 1, 0]
b = [9, 8, 7, 6, 5, 5, 6, 7, 8, 9]
Upvotes: 1
Views: 641
Reputation: 96454
No, arrays aren't threadsafe. This is luck in the sense that it works due to guarantees you weren't aware of.
In the JLS:
The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated.
Finding the thread died with isAlive counts for this. the synchronizes-with creates a happens-before relationship and makes sure the changes to the array are visible to the main thread. There was a data race between the two threads so it's not knowable what order their updates are be applied in but since they were doing the same thing it doesn't matter.
Sometimes code just happens to work by accident, on account of something causing a happens-before relationship, then that thing gets removed and stuff breaks mysteriously. Removing a call to System.out.println is an example, the call acquires a lock, which ends up making some change visible, then someone removes the println and is surprised that it doesn't work any more. See this question: Loop doesn't see value changed by other thread without a print statement
This kind of thing isn't something you want to rely on.
Upvotes: 0
Reputation: 269877
This is luck. Writes by one thread are not guaranteed to be visible to other threads unless the threads synchronize somehow. Arrays are not an exception.
There is an AtomicIntegerArray
type that can help you here.
While declaring an array field as volatile
doesn't extend to the elements of the array, there may be a way to establish a happens-before relationship using that. I'd have to think it through, but if it did work, it would be fairly brittle in the sense that changing the usage slightly could create a concurrency bug.
Upvotes: 5
Reputation: 2817
No, they are not. Threads will modify them how they want and there's a chance of a race condition. If you want more than 1 thread to operate on a collection at a time you need to use special thread safe collections, which have synchronisation built in, so you don't have to worry about it
The reason why your output seems correct is because there's only a small chance for this race condition to occur. You cannot protect with unit tests against it. You need to do some analytical work to prove that your code is thread safe or use a special framework for testing multithreaded stuff.
Does this answer your question ? Leave me a response in the comments
Upvotes: 0