Consider the following code sample:
private Object lock = new Object();
private volatile boolean doWait = true;
public void conditionalWait() throws Exception {
synchronized (lock) {
if (doWait) {
lock.wait();
}
}
}
public void cancelWait() throws Exception {
doWait = false;
synchronized (lock) {
lock.notifyAll();
}
}
If I understand the Java Memory Model correctly, then above code is not Thread-safe. It might very well block because the compiler might decide to rearrange the code as follows:
public void cancelWait() throws Exception {
synchronized (lock) {
lock.notifyAll();
}
doWait = false;
}
In this case it might happen that thread T1 calls the cancelWait() method, aquire the lock, call notifyAll() and release lock. After this a parallel thread T2 could call conditionalWait() and aquire the now available lock. The variable doWait still has value true, thus thread T2 executes lock.wait() and blocks.
Is my understanding correct? If not, then please provide according references from the Java Specification which disprove above scenario.
Is there a solution that resolves this issue that does not require pulling doWait into the synchronized block?
The question you are asking is actually
Can a monitor enter be re-ordered above a volatile store?
No, your transformation cannot happen. Take a look at the grid linked at the top of http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
First Operation: Volatile Store
Second Operation: Monitor Enter
Result: No
So the compiler cannot re-order as you suggest.
Your code is broken, but not because of reordering or visibility issues. Reordering problems occur in the absence of sufficient synchronization, which is not the case here. You have done everything possible, in terms of marking things volatile or synchronized, to let the JVM know to make the right things visible across threads.
Your problem here is that you're making several false assumptions:
You're thinking wait can never return until it gets a notification (this may not happen frequently, but it can happen, this is called a "spurious wakeup").
You're assuming that another thread can't barge in between the time the notification happens and the time that the waiting thread can reacquire the monitor. (Object#wait releases the monitor, and upon reacquiring it the thread needs to re-check what the current state is, instead of proceeding based on possibly outdated assumptions.)
You're assuming you can predict that the notify will happen after the wait (can't say whether that's true in this case since you didn't post a complete working example, but in general this is not something you want to assume).
There are lots of toy examples (thinking of the even-odd assignment) that get away with this because they are limited to only 2 threads, the race condition that causes spurious wakeups doesn't happen often on PC JVMs, and the program forces the two threads to act in lock-step so the order in which things happen is predictable. But those aren't realistic assumptions for the real world.
The fix for these bad assumptions is to wait in a loop using a condition variable to decide when you're done waiting (see this Oracle tutorial):
private final Object lock = new Object(); // final to emphasize this shouldn't change
private volatile boolean doWait = true;
public void conditionalWait() throws InterruptedException {
synchronized (lock) {
while (doWait) {
lock.wait();
}
}
}
public void cancelWait() {
doWait = false;
synchronized (lock) {
lock.notifyAll();
}
}
(I narrowed the exceptions thrown, the only thing thrown by notifyAll is IllegalMonitorStateException, which is unchecked and won't happen as long as you're using the right locks, it's only thrown as a result of programmer error.
Object#wait throws InterruptedException as well as IllegalMonitorStateException, it's ok to let it be thrown here.)
It would be just as well here to move the references to the doWait variable into the synchronized blocks, if all references to it are made while holding a lock then you don't need to make it volatile. But this isn't required.
The Java memory model guarantees sequential consistency when your program is correctly synchronized. Since your code above is correctly synchronized, then the reordering doesn't happen.
Happens Before Order
A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.
If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent (§17.4.3).
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.
This can be confusing since sequential consistency is defined previously in the inter-thread section of the spec (dealing with only a single thread).
Programs and Program Order
A set of actions is sequentially consistent if all actions occur in a total order (the execution order) that is consistent with program order, and furthermore, each read r of a variable v sees the value written by the write w to v such that:
w comes before r in the execution order, and
there is no other write w' such that w comes before w' and w' comes before r in the execution order.
Sequential consistency is a very strong guarantee that is made about visibility and ordering in an execution of a program. Within a sequentially consistent execution, there is a total order over all individual actions (such as reads and writes) which is consistent with the order of the program, and each individual action is atomic and is immediately visible to every thread.
If a program has no data races, then all executions of the program will appear to be sequentially consistent.
So what sequential consistency boils down to is that your program, when correctly synchronized, must appear to work like each read and write was completed exactly in the order specified in your program. No reordering are allowed (or allowed to be visible).
Normally when you talk about a write being reordered you're talking about a p-threads memory model, used by C++ (I think), which specifies when writes can and cannot be re-ordered past a memory barrier. It's a popular memory model and a lot of people know it.
Java doesn't have the concept of memory barriers. Java is similar, but not the same as, the p-thread spec, so don't get the two confused. In Java, either you have a program that works exactly in the order you specify in your program, or you have no guarantees at all if you don't synchronize. It's one or the other, and your case the write to the volatile has to appear in program order.
Re. your question in your comment below: I don't think it's that hard to find happens-before in the spec. Synchronization Order says:
Every execution has a synchronization order. A synchronization order is a total order over all of the synchronization actions of an execution. For each thread t, the synchronization order of the synchronization actions (§17.4.2) in t is consistent with the program order (§17.4.3) of t.
Synchronization actions induce the synchronized-with relation on actions, defined as follows:
An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).
And back to some definitions in Happens Before Order:
Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.
If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
If an action x synchronizes-with a following action y, then we also have hb(x, y).
So, the unlock of your monitor synchronized (lock) in cancelWait() synchronizes-with the lock acquire action in conditionalWait(). Synchroizes-with creates a happens-before relationship (see the very last line of that quote directly above). Therefore the assignment of doWait=false; must be visible when it is read in conditionalWait().
(Happens Before Order also says:
If hb(x, y) and hb(y, z), then hb(x, z).
so we know that if the volatile is assigned before the lock release, and a new lock acquire then happens after the lock release, it must be that the volatile assignment happens-before the lock acquire and is therefore visible.)
According JSL specification it's impossible
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5
also you could look into
Java memory model : compiler rearranging code lines
http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
Related
Imagine having a main thread which creates a HashSet and starts a lot of worker threads passing HashSet to them.
Just like in code below:
void main() {
final Set<String> set = new HashSet<>();
final ExecutorService threadExecutor =
Executors.newFixedThreadPool(10);
threadExecutor.submit(() -> doJob(set));
}
void doJob(final Set<String> pSet) {
// do some stuff
final String x = ... // doesn't matter how we received the value.
if (!pSet.contains(x)) {
synchronized (pSet) {
// double check to prevent multiple adds within different threads
if (!pSet.contains(x)) {
// do some exclusive work with x.
pSet.add(x);
}
}
}
// do some stuff
}
I'm wondering is it thread-safe to synchronize only on add method? Is there any possible issues if contains is not synchronized?
My intuition telling me this is fine, after leaving synchronized block changes made to set should be visible to all threads, but JMM could be counter-intuitive sometimes.
P.S. I don't think it's a duplicate of How to lock multiple resources in java multithreading
Even though answers to both could be similar, this question addresses more particular case.
I'm wondering is it thread-safe to synchronize only on the add method? Are there any possible issues if contains is not synchronized as well?
Short answers: No and Yes.
There are two ways of explaining this:
The intuitive explanation
Java synchronization (in its various forms) guards against a number of things, including:
Two threads updating shared state at the same time.
One thread trying to read state while another is updating it.
Threads seeing stale values because memory caches have not been written to main memory.
In your example, synchronizing on add is sufficient to ensure that two threads cannot update the HashSet simultaneously, and that both calls will be operating on the most recent HashSet state.
However, if contains is not synchronized as well, a contains call could happen simultaneously with an add call. This could lead to the contains call seeing an intermediate state of the HashSet, leading to an incorrect result, or worse. This can also happen if the calls are not simultaneous, due to changes not being flushed to main memory immediately and/or the reading thread not reading from main memory.
The Memory Model explanation
The JLS specifies the Java Memory Model which sets out the conditions that must be fulfilled by a multi-threaded application to guarantee that one thread sees the memory updates made by another. The model is expressed in mathematical language, and not easy to understand, but the gist is that visibility is guaranteed if and only if there is a chain of happens before relationships from the write to a subsequent read. If the write and read are in different threads, then synchronization between the threads is the primary source of these relationships. For example in
// thread one
synchronized (sharedLock) {
sharedVariable = 42;
}
// thread two
synchronized (sharedLock) {
other = sharedVariable;
}
Assuming that the thread one code is run before the thread two code, there is a happens before relationships between thread one releasing the lock and thread two acquiring it. With this and the "program order" relations, we can build a chain from the write of 42 to the assignment to other. This is sufficient to guarantee that other will be assigned 42 (or possibly a later value of the variable) and NOT any value in sharedVariable before 42 was written to it.
Without the synchronized block synchronizing on the same lock, the second thread could see a stale value of sharedVariable; i.e. some value written to it before 42 was assigned to it.
That code is thread safe for the the synchronized (pSet) { } part :
if (!pSet.contains(x)) {
synchronized (pSet) {
// Here you are sure to have the updated value of pSet
if (!pSet.contains(x)) {
// do some exclusive work with x.
pSet.add(x);
}
}
because inside the synchronized statement on the pSet object :
one and only one thread may be in this block.
and inside it, pSet has also its updated state guaranteed by the happens-before relationship with the synchronized keyword.
So whatever the value returned by the first if (!pSet.contains(x)) statement for a waiting thread, when this waited thread will wake up and enter in the synchronized statement, it will set the last updated value of pSet. So even if the same element was added by a previous thread, the second if (!pSet.contains(x)) would return false.
But this code is not thread safe for the first statement if (!pSet.contains(x)) that could be executed during a writing on the Set.
As a rule of thumb, a collection not designed to be thread safe should not be used to perform concurrently writing and reading operations because the internal state of the collection could be in a in-progress/inconsistent state for a reading operation that would occur meanwhile a writing operation.
While some no thread safe collection implementations accept such a usage in the facts, that is not guarantee at all that it will always be true.
So you should use a thread safe Set implementation to guarantee the whole thing thread safe.
For example with :
Set<String> pSet = ConcurrentHashMap.newKeySet();
That uses under the hood a ConcurrentHashMap, so no lock for reading and a minimal lock for writing (only on the entry to modify and not the whole structure).
No,
You don't know in what state the Hashset might be during add by another Thread. There might be fundamental changes ongoing, like splitting of buckets, so that contains may return false during the adding by another thread, even if the element would be there in a singlethreaded HashSet. In that case you would try to add an element a second time.
Even Worse Scenario: contains might get into an endless loop or throw an exception because of an temporary invalid state of the HashSet in the memory used by the two threads at the same time.
In the following code:
class A {
private int number;
public void a() {
number = 5;
}
public void b() {
while(number == 0) {
// ...
}
}
}
If method b is called and then a new thread is started which fires method a, then method b is not guaranteed to ever see the change of number and thus b may never terminate.
Of course we could make number volatile to resolve this. However for academic reasons let's assume that volatile is not an option:
The JSR-133 FAQs tells us:
After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory.
This sounds like I just need both a and b to enter and exit any synchronized-Block at all, no matter what monitor they use. More precisely it sounds like this...:
class A {
private int number;
public void a() {
number = 5;
synchronized(new Object()) {}
}
public void b() {
while(number == 0) {
// ...
synchronized(new Object()) {}
}
}
}
...would eliminate the problem and will guarantee that b will see the change to a and thus will also eventually terminate.
However the FAQs also clearly state:
Another implication is that the following pattern, which some people
use to force a memory barrier, doesn't work:
synchronized (new Object()) {}
This is actually a no-op, and your compiler can remove it entirely,
because the compiler knows that no other thread will synchronize on
the same monitor. You have to set up a happens-before relationship for
one thread to see the results of another.
Now that is confusing. I thought that the synchronized-Statement will cause caches to flush. It surely can't flush a cache to main memory in way that the changes in the main memory can only be seen by threads which synchronize on the same monitor, especially since for volatile which basically does the same thing we don't even need a monitor, or am I mistaken there? So why is this a no-op and does not cause b to terminate by guarantee?
The FAQ is not the authority on the matter; the JLS is. Section 17.4.4 specifies synchronizes-with relationships, which feed into happens-before relationships (17.4.5). The relevant bullet point is:
An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).
Since m here is the reference to the new Object(), and it's never stored or published to any other thread, we can be sure that no other thread will acquire a lock on m after the lock in this block is released. Furthermore, since m is a new object, we can be sure that there is no action that previously unlocked on it. Therefore, we can be sure that no action formally synchronizes-with this action.
Technically, you don't even need to do a full cache flush to be up to the JLS spec; it's more than the JLS requires. A typical implementation does that, because it's the easiest thing the hardware lets you do, but it's going "above and beyond" so to speak. In cases where escape analysis tells an optimizing compiler that we need even less, the compiler can perform less. In your example, escape analysis can could tell the compiler that the action has no effect (due to the reasoning above) and can be optimized out entirely.
the following pattern, which some people use to force a memory barrier, doesn't work:
It's not guaranteed to be a no-op, but the spec permits it to be a no-op. The spec only requires synchronization to establish a happens-before relationship between two threads when the two threads synchronize on the same object, but it actually would be easier to implement a JVM where the identity of the object did not matter.
I thought that the synchronized-Statement will cause caches to flush
There is no "cache" in the Java Language Specification. That's a concept that only exists in the details of some (well, O.K., virtually all) hardware platforms and JVM implementations.
My teacher in an upper level Java class on threading said something that I wasn't sure of.
He stated that the following code would not necessarily update the ready variable. According to him, the two threads don't necessarily share the static variable, specifically in the case when each thread (main thread versus ReaderThread) is running on its own processor and therefore doesn't share the same registers/cache/etc and one CPU won't update the other.
Essentially, he said it is possible that ready is updated in the main thread, but NOT in the ReaderThread, so that ReaderThread will loop infinitely.
He also claimed it was possible for the program to print 0 or 42. I understand how 42 could be printed, but not 0. He mentioned this would be the case when the number variable is set to the default value.
I thought perhaps it is not guaranteed that the static variable is updated between the threads, but this strikes me as very odd for Java. Does making ready volatile correct this problem?
He showed this code:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
There isn't anything special about static variables when it comes to visibility. If they are accessible any thread can get at them, so you're more likely to see concurrency problems because they're more exposed.
There is a visibility issue imposed by the JVM's memory model. Here's an article talking about the memory model and how writes become visible to threads. You can't count on changes one thread makes becoming visible to other threads in a timely manner (actually the JVM has no obligation to make those changes visible to you at all, in any time frame), unless you establish a happens-before relationship.
Here's a quote from that link (supplied in the comment by Jed Wesley-Smith):
Chapter 17 of the Java Language Specification defines the happens-before relation on memory operations such as reads and writes of shared variables. The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation. The synchronized and volatile constructs, as well as the Thread.start() and Thread.join() methods, can form happens-before relationships. In particular:
Each action in a thread happens-before every action in that thread that comes later in the program's order.
An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
A call to start on a thread happens-before any action in the started thread.
All actions in a thread happen-before any other thread successfully returns from a join on that thread.
He was talking about visibility and not to be taken too literally.
Static variables are indeed shared between threads, but the changes made in one thread may not be visible to another thread immediately, making it seem like there are two copies of the variable.
This article presents a view that is consistent with how he presented the info:
http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html
First, you have to understand a little something about the Java memory model. I've struggled a bit over the years to explain it briefly and well. As of today, the best way I can think of to describe it is if you imagine it this way:
Each thread in Java takes place in a separate memory space (this is clearly untrue, so bear with me on this one).
You need to use special mechanisms to guarantee that communication happens between these threads, as you would on a message passing system.
Memory writes that happen in one thread can "leak through" and be seen by another thread, but this is by no means guaranteed. Without explicit communication, you can't guarantee which writes get seen by other threads, or even the order in which they get seen.
...
But again, this is simply a mental model to think about threading and volatile, not literally how the JVM works.
Basically it's true, but actually the problem is more complex. Visibility of shared data can be affected not only by CPU caches, but also by out-of-order execution of instructions.
Therefore Java defines a Memory Model, that states under which circumstances threads can see consistent state of the shared data.
In your particular case, adding volatile guarantees visibility.
They are "shared" of course in the sense that they both refer to the same variable, but they don't necessarily see each other's updates. This is true for any variable, not just static.
And in theory, writes made by another thread can appear to be in a different order, unless the variables are declared volatile or the writes are explicitly synchronized.
Within a single classloader, static fields are always shared. To explicitly scope data to threads, you'd want to use a facility like ThreadLocal.
When you initialize static primitive type variable java default assigns a value for static variables
public static int i ;
when you define the variable like this the default value of i = 0;
thats why there is a possibility to get you 0.
then the main thread updates the value of boolean ready to true. since ready is a static variable , main thread and the other thread reference to the same memory address so the ready variable change. so the secondary thread get out from while loop and print value.
when printing the value initialized value of number is 0. if the thread process has passed while loop before main thread update number variable. then there is a possibility to print 0
#dontocsata
you can go back to your teacher and school him a little :)
few notes from the real world and regardless what you see or be told.
Please NOTE, the words below are regarding this particular case in the exact order shown.
The following 2 variable will reside on the same cache line under virtually any know architecture.
private static boolean ready;
private static int number;
Thread.exit (main thread) is guaranteed to exit and exit is guaranteed to cause a memory fence, due to the thread group thread removal (and many other issues). (it's a synchronized call, and I see no single way to be implemented w/o the sync part since the ThreadGroup must terminate as well if no daemon threads are left, etc).
The started thread ReaderThread is going to keep the process alive since it is not a daemon one!
Thus ready and number will be flushed together (or the number before if a context switch occurs) and there is no real reason for reordering in this case at least I can't even think of one.
You will need something truly weird to see anything but 42. Again I do presume both static variables will be in the same cache line. I just can't imagine a cache line 4 bytes long OR a JVM that will not assign them in a continuous area (cache line).
I am learning multi-thread programming from 'Java Concurrency in Practice'.
At one point, book says that even an innocuous looking increment operation is not thread safe as it consists of three different operations...read,modify and write.
class A {
private void int c;
public void increment() {
++c;
}
}
So increment statement is not atomic, hence not thread safe.
My question is that if an environment is really concurrent (ie multiple threads are able to execute their program statements exactly at same time) then a statement which is really atomic also can't be thread safe as multiple threads can read same value.
So how can having an atomic statement help in achieving thread safety in a concurrent environment?
True concurrency does not exist when it comes to modifying state.
This post has some good descriptions of Concurrency and Parallelism.
As stated by #RitchieHindle in that post:
Concurrency is when two tasks can start, run, and complete in overlapping time periods. It doesn't necessarily mean they'll ever both be running at the same instant. Eg. multitasking on a single-core machine.
As an example, the danger of non-atomic operations is that one thread might read the value, another might modify the value, and then the original thread might modify and write the value (thus negating the modification the second thread did).
Atomic operations do not allow other operations access to the state while in the middle of the atomic operation. If, for example, the increment operator were atomic, it would read, modify, and write without any other thread having access to that variables state while those operations took place.
You can use AtomicInteger. The linked Javadoc says (in part) that it is an int value that may be updated atomically. AtomicInteger also implements addAndGet(int) which atomically adds the given value to the current value
private AtomicInteger ai = new AtomicInteger(1); // <-- or another initial value
public int increment() {
return ai.addAndGet(1); // <-- or another increment value
}
That can (for example) allow you to guarantee write order consistency for multiple threads. Consider, ai might represent (or include) some static (or global) resource. If a value is thread local then you don't need to consider atomicity.
Can the synchronization statements be reordered. i.e :
Can :
synchronized(A) {
synchronized(B) {
......
}
}
become :
synchronized(B) {
synchronized(A) {
......
}
}
Can the synchronization statements be reordered?
I assume you are asking if the compiler can reorder the synchronized blocks so the lock order happens in a different order than the code.
The answer is no. A synchronized block (and a volatile field access) impose ordering restrictions on the compiler. In your case, you cannot move a monitor-enter before another monitor-enter nor a monitor-exit after another monitor-exit. See the grid below.
To quote from JSR 133 (Java Memory Model) FAQ:
It is not possible, for example, for the compiler to move your code before an acquire or after a release. When we say that acquires and releases act on caches, we are using shorthand for a number of possible effects.
Doug Lea's JSR-133 Cookbook has a grid which shows the reordering possibilities. A blank entry in the grid means that reordering is allowed. In your case, entering a synchronized block is a "MonitorEnter" (same reordering limitations as loading of a volatile field) and exiting a synchronized block is a "MonitorExit" (same as storing to a volatile field).
Yes and no.
The order must be consistent.
Suppose you are creating a transaction between two bank accounts, and always grab the sender's lock first, then grab the receiver's lock. Problem is - say both Dan and Bob want to transfer money to each other at the same time.
Thread 1 might grab Dan's lock, as it processes Dan's transaction to Bob.
Then thread 2 grab's Bob's lock, as it processes Bob's transaction to Dan.
Then, bam, deadlock.
The morals are:
Lock less.
Read Java: Concurrency in Practice. My example is taken from there. I like arguing about the merits of books in programming as much as the next guy, but it's pretty rare you get comprehensive coverage of a difficult topic between two covers, so enjoy it.
So this is the part of the answer where I guess at other things you might have been trying to ask instead, because the expectation is firmly on me that I act psychic.
The JVM will not acquire the locks in an order different from which you have programmed. How do I know this? Because otherwise it would not be possible to solve the problem in the first half of my answer.
Synchronized statements are never reordered by the compiler as it has a big effect on what ends up happening.
Synchronized blocks are used to obtain a lock on the specific Object placed between the synchronized parenthesis.
private final Object LOCK_1 = new Object();
public void foo(){
synchronized(LOCK_1){
//code here...
}
}
Obtains the lock for Object LOCK_1 and releases it when the synchronization block completes. Since synchronization blocks are used to guard against concurrent access it may be sometimes required to use multiple locks especially when multiple thread-unsafe objects are being written/read to/from.
Consider the following code that uses a nested synchronization block:
private final Object LOCK_1 = new Object();
private final Object LOCK_2 = new Object();
public void bar(){
synchronized(LOCK_1){
//Point A
synchronized(LOCK_2){
//Point B
}
//Point C
}
//Point D
}
If we look at points A,B,C,D we can realize why the order of synchronization matters.
First at point A, the lock for LOCK_1 is obtained therefore any other threads trying to obtain LOCK_1 is put into a queue.
At point B, the currently executing thread owns the lock for both LOCK_1 and LOCK_2.
At point C, the currently executing thread has released the lock for LOCK_2
At point D, the currently executing thread has released all locks.
If we flip this example around and decided to put LOCK_2 on the outer block, you will realize that the thread's order of obtaining locks changes which has a big effect on what it ends up doing. Normally, when I make programs with synchronization blocks I use one MUTEX object per thread-unsafe resource I am accessing (or one MUTEX per group). Say I want to read from a stream using LOCK_1 and write to a stream using LOCK_2. It would be illogical to think that swapping the locking order around means the same thing.
Consider that LOCK_2 (the writing lock) is being held by another thread. If we have LOCK_1 on the outer block the currently executing thread can at least process all the reading code before being put into a queue for the writing lock (essentially, the ability to execute code at point A). If we flipped the order of the locks around, the currently executing thread will end up having to wait for the writing is complete, then proceed onto reading and writing whilst holding onto the writing lock (all the way through reading too).
Another problem that comes up when the order of locks are switched (and not consistently, some code has LOCK_1 first and others have LOCK_2 first). Consider that two threads both eagerly try to execute code which have different locking orders. Thread 1 obtains LOCK_1 in the outer block and thread 2 obtains LOCK_2 from the outer block. Now when thread 1 tries to obtain LOCK_2, it can't since thread 2 has it. And when thread 2 tries to obtain LOCK_1, it can't either because thread 1 has it. The two threads essentially block on each other forever, forming a deadlock situation.
To answer your question, if you want to lock on two objects immediately without doing any sort of processing between locks then the order is irrelevant (essentially no processing at point A or C). HOWEVER it is essential to keep the order consistent throughout your program as to avoid deadlocking.