Using volatile collections and arrays in Java - java

Imagine we have
volatile int publisher = 0;
volatile List<String> list = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
volatile String[] array = {"Buenos Aires", "Córdoba", "La Plata"};
As far as I understand.
Initial values in list and array are published correctly and are visible to all the reading threads.
All values added after the initialization are not safe-published.
Still we can read and publish them safely using
//in Thread 1
list.add("Safe City");
array[2] = "Safe city";
publisher = 1;
//in Thread2
if(publisher == 1) {
String city = list.get(3);
city = array[2];
}
Am I right?

Looking strictly at what the code is doing, and nothing more, and assessing it only in terms of the memory model, you are correct. The write to the volatile variable publisher in thread 1 and the read from the volatile variable in thread 2 establish a happens-before relationship, so all previous writes from thread 1 will be visible to subsequent reads from thread 2.
As CupawnTae noted, it's not necessary for the list and the array to be volatile in order for this to hold. Only publisher needs to be volatile.
Looking at this from a broader perspective, it's very difficult to extend this code to do anything else. (Set aside the fact that the List returned by Arrays.asList cannot have elements added to it; assume it's an ArrayList instead.) Presumably thread 1, or some other thread, will want to continue to add elements to the list. If this happens to cause the ArrayList to reallocate its underlying array, this might occur while thread 2 is still reading results from the previous addition. Thus, inconsistent state might be visible to thread 2.
Suppose further that thread 1 wants to do subsequent updates. It will have to set publisher to some other value, say 2. Now how do reading threads know what the correct value is to test for? Well, they can read the expected value from some other volatile variable....
It's undoubtedly possible to construct a scheme where thread 1 can write to a list (or array) at will, and thread 2 will never see anything but consistent snapshots, but you have to be exceptionally careful about memory visiblity at every step of the way. At a certain point it's easier just to use locks.

That is correct, but...
The volatile keyword on the list and array are irrelevant here - the fact that you write a value to the volatile publisher after you write the other values, and read back that value in your if condition before reading the other values in the second thread guarantees you memory consistency between those threads.
If you remove the volatile keyword from the list and array, your code will still be safe.
If you remove the publisher variable write/read, then the add operation* and array assignment are no longer safe.
And yes, the initial assignment to the variables is also safe.
* which is actually invalid on that particular list anyway as pointed out by Stuart Marks, but let's assume it's e.g. an ArrayList

The "publishing" happens between the thread that sets the volatile value and teh thread that gets it.
You need to both
publisher = 1;
in one thread and
int local = publisher;
in the other.

Have you considered using synchronized blocks to provide locking of the data structures that you're trying to read/write to/from?
//in Thread 1
synchronized(someLockingMonitor) {
list.add("Safe City");
array[2] = "Safe city";
}
//in Thread2
synchronized(someLockingMonitor) {
String city = list.get(3);
city = array[2];
}
This will however force any thread wishing to access one of the blocks, to wait until any other thread currently executing inside one of these block to leave the block.
If concurrency is important to you, i.e. you really want different threads reading and writing at the same time, have a look at the concurrent collections in java.util.concurrent.

Related

how synchronized keyword works internally

I read the below program and answer in a blog.
int x = 0;
boolean bExit = false;
Thread 1 (not synchronized)
x = 1;
bExit = true;
Thread 2 (not synchronized)
if (bExit == true)
System.out.println("x=" + x);
is it possible for Thread 2 to print “x=0”?
Ans : Yes ( reason : Every thread has their own copy of variables. )
how do you fix it?
Ans: By using make both threads synchronized on a common mutex or make both variable volatile.
My doubt is : If we are making the 2 variable as volatile then the 2 threads will share the variables from the main memory. This make a sense, but in case of synchronization how it will be resolved as both the thread have their own copy of variables.
Please help me.
This is actually more complicated than it seems. There are several arcane things at work.
Caching
Saying "Every thread has their own copy of variables" is not exactly correct. Every thread may have their own copy of variables, and they may or may not flush these variables into the shared memory and/or read them from there, so the whole thing is non-deterministic. Moreover, the very term flushing is really implementation-dependent. There are strict terms such as memory consistency, happens-before order, and synchronization order.
Reordering
This one is even more arcane. This
x = 1;
bExit = true;
does not even guarantee that Thread 1 will first write 1 to x and then true to bExit. In fact, it does not even guarantee that any of these will happen at all. The compiler may optimize away some values if they are not used later. The compiler and CPU are also allowed to reorder instructions any way they want, provided that the outcome is indistinguishable from what would happen if everything was really in program order. That is, indistinguishable for the current thread! Nobody cares about other threads until...
Synchronization comes in
Synchronization does not only mean exclusive access to resources. It is also not just about preventing threads from interfering with each other. It's also about memory barriers. It can be roughly described as each synchronization block having invisible instructions at the entry and exit, the first one saying "read everything from the shared memory to be as up-to-date as possible" and the last one saying "now flush whatever you've been doing there to the shared memory". I say "roughly" because, again, the whole thing is an implementation detail. Memory barriers also restrict reordering: actions may still be reordered, but the results that appear in the shared memory after exiting the synchronized block must be identical to what would happen if everything was indeed in program order.
All that only works, of course, only if both blocks use the same locking object.
The whole thing is described in details in Chapter 17 of the JLS. In particular, what's important is the so-called "happens-before order". If you ever see in the documentation that "this happens-before that", it means that everything the first thread does before "this" will be visible to whoever does "that". This may even not require any locking. Concurrent collections are a good example: one thread puts there something, another one reads that, and that magically guarantees that the second thread will see everything the first thread did before putting that object into the collection, even if those actions had nothing to do with the collection itself!
Volatile variables
One last warning: you better give up on the idea that making variables volatile will solve things. In this case maybe making bExit volatile will suffice, but there are so many troubles that using volatiles can lead to that I'm not even willing to go into that. But one thing is for sure: using synchronized has much stronger effect than using volatile, and that goes for memory effects too. What's worse, volatile semantics changed in some Java version so there may exist some versions that still use the old semantics which was even more obscure and confusing, whereas synchronized always worked well provided you understand what it is and how to use it.
Pretty much the only reason to use volatile is performance because synchronized may cause lock contention and other troubles. Read Java Concurrency in Practice to figure all that out.
Q & A
1) You wrote "now flush whatever you've been doing there to the shared
memory" about synchronized blocks. But we will see only the variables
that we access in the synchronize block or all the changes that the
thread call synchronize made (even on the variables not accessed in the
synchronized block)?
Short answer: it will "flush" all variables that were updated during the synchronized block or before entering the synchronized block. And again, because flushing is an implementation detail, you don't even know whether it will actually flush something or do something entirely different (or doesn't do anything at all because the implementation and the specific situation already somehow guarantee that it will work).
Variables that wasn't accessed inside the synchronized block obviously won't change during the execution of the block. However, if you change some of those variables before entering the synchronized block, for example, then you have a happens-before relationship between those changes and whatever happens in the synchronized block (the first bullet in 17.4.5). If some other thread enters another synchronized block using the same lock object then it synchronizes-with the first thread exiting the synchronized block, which means that you have another happens-before relationship here. So in this case the second thread will see the variables that the first thread updated prior to entering the synchronized block.
If the second thread tries to read those variables without synchronizing on the same lock, then it is not guaranteed to see the updates. But then again, it isn't guaranteed to see the updates made inside the synchronized block as well. But this is because of the lack of the memory-read barrier in the second thread, not because the first one didn't "flush" its variables (memory-write barrier).
2) In this chapter you post (of JLS) it is written that: "A write to a
volatile field (§8.3.1.4) happens-before every subsequent read of that
field." Doesn't this mean that when the variable is volatile you will
see only changes of it (because it is written write happens-before
read, not happens-before every operation between them!). I mean
doesn't this mean that in the example, given in the description of the
problem, we can see bExit = true, but x = 0 in the second thread if
only bExit is volatile? I ask, because I find this question here: http://java67.blogspot.bg/2012/09/top-10-tricky-java-interview-questions-answers.html
and it is written that if bExit is volatile the program is OK. So the
registers will flush only bExits value only or bExits and x values?
By the same reasoning as in Q1, if you do bExit = true after x = 1, then there is an in-thread happens-before relationship because of the program order. Now since volatile writes happen-before volatile reads, it is guaranteed that the second thread will see whatever the first thread updated prior to writing true to bExit. Note that this behavior is only since Java 1.5 or so, so older or buggy implementations may or may not support this. I have seen bits in the standard Oracle implementation that use this feature (java.concurrent collections), so you can at least assume that it works there.
3) Why monitor matters when using synchronized blocks about memory
visibility? I mean when try to exit synchronized block aren't all
variables (which we accessed in this block or all variables in the
thread - this is related to the first question) flushed from registers
to main memory or broadcasted to all CPU caches? Why object of
synchronization matters? I just cannot imagine what are relations and
how they are made (between object of synchronization and memory).
I know that we should use the same monitor to see this changes, but I
don't understand how memory that should be visible is mapped to
objects. Sorry, for the long questions, but these are really
interesting questions for me and it is related to the question (I
would post questions exactly for this primer).
Ha, this one is really interesting. I don't know. Probably it flushes anyway, but Java specification is written with high abstraction in mind, so maybe it allows for some really weird hardware where partial flushes or other kinds of memory barriers are possible. Suppose you have a two-CPU machine with 2 cores on each CPU. Each CPU has some local cache for every core and also a common cache. A really smart VM may want to schedule two threads on one CPU and two threads on another one. Each pair of the threads uses its own monitor, and VM detects that variables modified by these two threads are not used in any other threads, so it only flushes them as far as the CPU-local cache.
See also this question about the same issue.
4) I thought that everything before writing a volatile will be up to
date when we read it (moreover when we use volatile a read that in
Java it is memory barrier), but the documentation don't say this.
It does:
17.4.5.
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
If hb(x, y) and hb(y, z), then hb(x, z).
A write to a volatile field (§8.3.1.4) happens-before every subsequent
read of that field.
If x = 1 comes before bExit = true in program order, then we have happens-before between them. If some other thread reads bExit after that, then we have happens-before between write and read. And because of the transitivity, we also have happens-before between x = 1 and read of bExit by the second thread.
5) Also, if we have volatile Person p does we have some dependency
when we use p.age = 20 and print(p.age) or have we memory barrier in
this case(assume age is not volatile) ? - I think - No
You are correct. Since age is not volatile, then there is no memory barrier, and that's one of the trickiest things. Here is a fragment from CopyOnWriteArrayList, for example:
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
Here, getArray and setArray are trivial setter and getter for the array field. But since the code changes elements of the array, it is necessary to write the reference to the array back to where it came from in order for the changes to the elements of the array to become visible. Note that it is done even if the element being replaced is the same element that was there in the first place! It is precisely because some fields of that element may have changed by the calling thread, and it's necessary to propagate these changes to future readers.
6) And is there any happens before 2 subsequent reads of volatile
field? I mean does the second read will see all changes from thread
which reads this field before it(of course we will have changes only
if volatile influence visibility of all changes before it - which I am
a little confused whether it is true or not)?
No, there is no relationship between volatile reads. Of course, if one thread performs a volatile write and then two other thread perform volatile reads, they are guaranteed to see everything at least up to date as it was before the volatile write, but there is no guarantee of whether one thread will see more up-to-date values than the other. Moreover, there is not even strict definition of one volatile read happening before another! It is wrong to think of everything happening on a single global timeline. It is more like parallel universes with independent timelines that sometimes sync their clocks by performing synchronization and exchanging data with memory barriers.
It depends on the implementation which decides if threads will keep a copy of the variables in their own memory. In case of class level variables threads have a shared access and in case of local variables threads will keep a copy of it. I will provide two examples which shows this fact , please have a look at it.
And in your example if I understood it correctly your code should look something like this--
package com.practice.multithreading;
public class LocalStaticVariableInThread {
static int x=0;
static boolean bExit = false;
public static void main(String[] args) {
Thread t1=new Thread(run1);
Thread t2=new Thread(run2);
t1.start();
t2.start();
}
static Runnable run1=()->{
x = 1;
bExit = true;
};
static Runnable run2=()->{
if (bExit == true)
System.out.println("x=" + x);
};
}
Output
x=1
I am getting this output always. It is because the threads share the variable and the when it is changed by one thread other thread can see it. But in real life scenarios we can never say which thread will start first, since here the threads are not doing anything we can see the expected result.
Now take this example--
Here if you make the i variable inside the for-loop` as static variable then threads won t keep a copy of it and you won t see desired outputs, i.e. the count value will not be 2000 every time even if u have synchronized the count increment.
package com.practice.multithreading;
public class RaceCondition2Fixed {
private int count;
int i;
/*making it synchronized forces the thread to acquire an intrinsic lock on the method, and another thread
cannot access it until this lock is released after the method is completed. */
public synchronized void increment() {
count++;
}
public static void main(String[] args) {
RaceCondition2Fixed rc= new RaceCondition2Fixed();
rc.doWork();
}
private void doWork() {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for ( i = 0; i < 1000; i++) {
increment();
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for ( i = 0; i < 1000; i++) {
increment();
}
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*if we don t use join then count will be 0. Because when we call t1.start() and t2.start()
the threads will start updating count in the spearate threads, meanwhile the main thread will
print the value as 0. So. we need to wait for the threads to complete. */
System.out.println(Thread.currentThread().getName()+" Count is : "+count);
}
}

Two threads accessing the same ArrayList at the same time?

I have the following code in thread 1:
synchronized (queues.get(currentQueue)) { //line 1
queues.get(currentQueue).add(networkEvent); //line 2
}
and the following in thread 2:
synchronized (queues.get(currentQueue)) {
if (queues.get(currentQueue).size() > 10) {
currentQueue = 1;
}
}
Now to my question: The currentQueue variable currently has the value of 0. When thread 2 changes the value of currentQueue to 1 and thread 1 waits at line 1 (because of the synchronized), does thread 1 then use the updated currentQueue value in line 2 after thread 2 has finished (that's what I want to).
The answer to the question is that it depends. I assume there is other chunk of code that increments the currentQueue variable. This being the case, the lock is happening not at the 'currentQueue' variable and neither is it happening at the collection of 'queues', but rather it is happening on one of the 10 queues (or however many you have) in the 'queues' collection.
Hence, if both threads happen to access the same queue (say queue 5), then the answer to your question is yes. However, for that to happen is one in ten chance (one in x chance, where x = the number or queues in the 'queues' collection). Therefore, if the threads access different queues, then the answer is no.
The correct answer to your question is: The result is undefined.
Your monitor object is queues.get(currentQueue), but since currentQueue is variable, your monitor is variable, therefore the state it is currently in is more or less random. Effectively this code would break eventually.
A simple way to fix it would be a function like this:
protected synchronized QueueType getCurrentQueue() {
return queues.get(currentQueue);
}
However this is still a bad way of implementing the whole thing. You should either try to eliminate the synchronization completely through the use of a concurrent Queue (like ConcurrentLinkedQueue) or work with a lock/final monitor object.
final Object queueLock = new Object();
...
synchronized(queueLock) {
queues.get(currentQueue).add(networkEvent);
}
Note that you will have to use that locking every time you access queues or currentQueue as both define the dataset you are using.
Assuming you have no other thread will change the value of currentQueue, yes Thread 1 will end up using the queue pointed to by the updated value of currentQueue, since you're invoking queues.get(currentQueue) once again in the body of the synchronized block. This however doesn't mean that your synchronization is sound. You actually should synchronize on currentQueue, since it seems to be the shared key to access the current queue.
Also remember when you use synchronize you're synchronizing on the reference of the variable, and not its value. So if you reassign a new object to it, your synchronization doesn't make sense anymore.

How atomicity is achieved in the classes defined in java.util.concurrent.atomic package?

I was going through the source code of java.util.concurrent.atomic.AtomicInteger to find out how atomicity is achieved by the atomic operations provided by the class. For instance AtomicInteger.getAndIncrement() method source is as follows
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
I am not able to understand the purpose of writing the sequence of operations inside a infinite for loop. Does it serve any special purpose in Java Memory Model (JMM). Please help me find a descriptive understanding. Thanks in advance.
I am not able to understand the purpose of writing the sequence of operations inside a infinite for loop.
The purpose of this code is to ensure that the volatile field gets updated appropriately without the overhead of a synchronized lock. Unless there are a large number of threads all competing to update this same field, this will most likely spin a very few times to accomplish this.
The volatile keyword provides visibility and memory synchronization guarantees but does not in itself ensure atomic operations with multiple operations (test and set). If you are testing and then setting a volatile field there are race-conditions if multiple threads are trying to perform the same operation at the same time. In this case, if multiple threads are trying to increment the AtomicInteger at the same time, you might miss one of the increments. The concurrent code here uses the spin loop and the compareAndSet underlying methods to make sure that the volatile int is only updated to 4 (for example) if it still is equal to 3.
t1 gets the atomic-int and it is 0.
t2 gets the atomic-int and it is 0.
t1 adds 1 to it
t1 atomically tests to make sure it is 0, it is, and stores 1.
t2 adds 1 to it
t2 atomically tests to make sure it is 0, it is not, so it has to spin and try again.
t2 gets the atomic-int and it is 1.
t2 adds 1 to it
t2 atomically tests to make sure it is 1, it is, and stores 2.
Does it serve any special purpose in Java Memory Model (JMM).
No, it serves the purpose of the class and method definitions and uses the JMM and the language definitions around volatile to achieve its purpose. The JMM defines what the language does with the synchronized, volatile, and other keywords and how multiple threads interact with cached and central memory. This is mostly about native code interactions with operating system and hardware and is rarely, if ever, about Java code.
It is the compareAndSet(...) method which gets closer to the JMM by calling into the Unsafe class which is mostly native methods with some wrappers:
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
I am not able to understand the purpose of writing the sequence of
operations inside a infinite for loop.
To understand why it is in an infinite loop I find it helpful to understand what the compareAndSet does and how it may return false.
Atomically sets the value to the given updated value if the current
value == the expected value.
Parameters:
expect - the expected value
update - the new value
Returns:
true if successful. False return indicates that the actual value was not
equal to the expected value
So you read the Returns message and ask how is that possible?
If two threads are invoking incrementAndGet at close to the same time, and they both enter and see the value current == 1. Both threads will create a thread-local next == 2 and try to set via compareAndSet. Only one thread will win as per documented and the thread that loses must try again.
This is how CAS works. You attempt to change the value if you fail, try again, if you succeed then continue on.
Now simply declaring the field as volatile will not work because incrementing is not atomic. So something like this is not safe from the scenario I explained
volatile int count = 0;
public int incrementAndGet(){
return ++count; //may return the same number more than once.
}
Java's compareAndSet is based on CPU compare-and-swap (CAS) instructions see http://en.wikipedia.org/wiki/Compare-and-swap. It compares the contents of a memory location to a given value and, only if they are the same, modifies the contents of that memory location to a given new value.
In case of incrementAndGet we read the current value and call compareAndSet(current, current + 1). If it returns false it means that another thread interfered and changed the current value, which means that our attempt failed and we need to repeat the whole cycle until it succeeds.

is .get() operation in arraylist/atomic double array (Google Guava) thread-safe?

Following is one of the main operations in my java code:
AtomicDoubleArray array1 = new AtomicDoubleArray(25);
for(int i =0 ; i< array1.size(); i++){
double a = array1.get(i)*0.001;
double b = a+ array1.get(i);
array1.set(b);
}
Is the above code is thread safe? If not i can I make above code thread safe?I would like not to keep locking while reading elements but locking during setting the value of each of the components.It means a number of threads can set the different componets of array1.
Is the above code is thread safe?
That depends on what you mean with thread safety. Each individual get() and set() operation should be thread safe, but multiple threads could be calling this method concurrently, so the individual array entries could be reassigned by a second thread before the first thread completes the iteration. There's nothing you can do about that except synchronizing on a common Object (which could either be the array or some other dedicated lock Object)
I would like not to keep locking while reading elements but locking
during setting the value of each of the components.It means a number
of threads can set the different componets of array1.
If I understand this right, you can use your code as-is without additional locking (see above), except for this part:
array1.set(b);
which needs to read:
array1.set(i, b);
You may get different values on the two consecutive calls to to array1.get(i). If you want to avoid synchronisation, have a look at copy on write data structures (e.g. CopyOnWriteArrayList - http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html)

Java thread safety of list

I have a List, which is to be used either in thread-safe context or in a non thread-safe one. Which one will it be, is impossible to determine in advance.
In such special case, whenever the list enters non-thread-safe context, I wrap it using
Collections.synchronizedList(...)
But I don't want to wrap it, if doesn't enter non-thread-safe context. F.e., because list is huge and used intensively.
I've read about Java, that its optimization policy is strict about multi-threading - if you don't synchronize your code correctly, it is not guaranteed to be executed correctly in inter-thread context - it can reorganize code significantly, providing consistency in context of only one thread (see http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.3). F.e.,
op1;
op2;
op3;
may be reorganized in
op3;
op2;
op1;
, if it produces same result (in one-thread context).
Now I wonder, if I
fill my list before wrapping it by synchronizedList,
then wrap it up,
then use by different thread
, - is there a possibility, that different thread will see this list filled only partially or not filled at all? Might JVM postpone (1) till after (3)? Is there a correct and fast way to make (big) List being non-thread-safe to become thread-safe?
When you give your list to another thread by thread-safe means (for example using a synchronized block, a volatile variable or an AtomicReference), it is guaranteed that the second thread sees the whole list in the state it was when transferring (or any later state, but not an earlier state).
If you don't change it afterwards, you also don't need your synchronizedList.
Edit (after some comments, to backup my claim):
I assume the following:
we have a volatile variable list.
volatile List<String> list = null;
Thread A:
creates a List L and fills L with elements.
sets list to point to L (this means writes L to list)
does no further modifications on L.
Sample source:
public void threadA() {
List<String> L = new ArrayList<String>();
L.add("Hello");
L.add("World");
list = l;
}
Thread B:
reads K from list
iterates over K, printing the elements.
Sample source:
public void threadB() {
List<String> K = list;
for(String s : K) {
System.out.println(s);
}
}
All other threads do not touch the list.
Now we have this:
The actions 1-A and 2-A in Thread A are ordered by program order so 1 comes before 2.
The action 1-B and 2-B in Thread B are ordered by program order so 1 comes before 2.
The action 2-A in Thread A and action 1-B in Thread are ordered by synchronization order, so 2-A comes before 1-B, since
A write to a volatile variable (§8.3.1.4) v synchronizes-with all subsequent reads of v by any thread (where subsequent is defined according to the synchronization order).
The happens-before-order is the transitive closure of the program orders of the individual threads and the synchronization order. So we have:
1-A happens-before 2-A happens-before 1-B happens-before 2-B
and thus 1-A happens-before 2-B.
Finally,
If one action happens-before another, then the first is visible to and ordered before the second.
So our iterating thread really can see the whole list, and not only some parts of it.
So, transmitting the list with a single volatile variable is sufficient, and we don't need synchronization in this simple case.
One more edit (here, since I have more formatting freedom than in the comments) about the program order of Thread A. (I also added some sample Code above.)
From the JLS (section program order):
Among all the inter-thread actions performed by each thread t, the program order
of t is a total order that reflects the order in which these actions would be
performed according to the intra-thread semantics of t.
So, what are the intra-thread semantics of thread A?
Some paragraphs above:
The memory model determines what values can be read at every point in the program.
The actions of each thread in isolation must behave as governed by the semantics
of that thread, with the exception that the values seen by each read are
determined by the memory model. When we refer to this, we say that the program
obeys intra-thread semantics. Intra-thread semantics are the semantics for
single threaded programs, and allow the complete prediction of the behavior of
a thread based on the values seen by read actions within the thread. To determine
if the actions of thread t in an execution are legal, we simply evaluate the
implementation of thread t as it would be performed in a single threaded context,
as defined in the rest of this specification.
The rest of this specification includes section 14.2 (Blocks):
A block is executed by executing each of the local variable declaration
statements and other statements in order from first to last (left to right).
So, the program order is indeed the order in which the statements/expressions
are given in the program source code.
Thus, in our example source, the memory actions create a new ArrayList, add "Hello", add "World", and assign to list (the first three consist of more subactions) indeed are in this program order.
(The VM does not have to execute the actions in this order, but this program order still contributes to the happens-before order, and thus to the visibility to other threads.)
If you fill your list and then wrap it in the same thread, you'll be safe.
However there are several things to bear in mind:
Collections.synchronizedList() only guarantees you a low-level thread safety. Complex operations, like if ( !list.contains( elem ) ) list.add( elem ); will still need custom synchronization code.
Even this guarantee is void if any thread can obtain a reference to the original list. Make sure this doesn't happen.
Get the functionality right first, then you can start worrying about synchronization being too slow. I very rarely encountered code where the speed of Java synchronization was a serious factor.
Update: I'd like to add a few excerpts from the JLS to hopefully clarify matters a bit.
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
This is why filling the list and then wrapping it in the same thread is a safe option. But more importantly:
This is an extremely strong guarantee for programmers. Programmers do not need to reason about reorderings to determine that their code contains data races. Therefore they do not need to reason about reorderings when determining whether their code is correctly synchronized. Once the determination that the code is correctly synchronized is made, the programmer does not need to worry that reorderings will affect his or her code.
The message is clear: make sure that your program, executed in the order which you wrote your code in, doesn't contain data races, and don't worry about reordering.
If the traverses happens more often than writing I'd look into CopyOnWriteArrayList.
A thread-safe variant of ArrayList in
which all mutative operations (add,
set, and so on) are implemented by
making a fresh copy of the underlying
array.
Take a look at how AtomicInteger (and the likes) are implemented to be thread safe & not synchronized. The mechanism does not introduce synchronization, but if one is needed, it handles it gracefully.

Categories

Resources