In Java critical sections, what should I synchronize on?
First, note that the following code snippets are identical.
public void foo() {
synchronized (this) {
// do something thread-safe
}
}
and:
public synchronized void foo() {
// do something thread-safe
}
do exactly the same thing. No preference for either one of them except for code readability and style.
When you do synchronize methods or blocks of code, it's important to know why you are doing such a thing, and what object exactly you are locking, and for what purpose.
Also note that there are situations in which you will want to client-side synchronize blocks of code in which the monitor you are asking for (i.e. the synchronized object) is not necessarily this
, like in this example :
Vector v = getSomeGlobalVector();
synchronized (v) {
// some thread-safe operation on the vector
}
I suggest you get more knowledge about concurrent programming, it will serve you a great deal once you know exactly what's happening behind the scenes. You should check out Concurrent Programming in Java, a great book on the subject. If you want a quick dive-in to the subject, check out Java Concurrency @ Sun
Why does this critical section not work in Java?
I ran this code myself and when you have the synchronized blocks set up, it works (the yield()
call returns quickly), but when you remove them, it doesn't (the app hangs, the yield()
call seemingly never returning).
This is expected behaviour, more or less. If this code did return swiftly from that yield() call, that would ALSO be expected behaviour.
Welcome to the Java Memory Model.
Every thread gets an unfair coin. it is unfair, in that it is free to screw with you, and flip the same way every time, making it look like something works reliably, juuuust for it to fail when you're giving that demo to that important client. The basic rule is simple. If a thread ever flips the coin and the way your code runs differs depending on how it lands, you lost the game: You have a bug, and writing a test that catches it is virtually impossible. Writing threading code like this is therefore an act that requires extreme discipline.
The thread will flip the coin anytime it reads or writes a field. Each thread has a custom local clone copy of every field of every object* which it will read from and write to. But everytime it does so, it flips that evil coin. If the coin lands heads, it will arbitrarily copy its values to some or all other thread's copies, or copy the values from some other thread's local copy to itself. On tails, it doesn't do that and just uses its local copy.
In this case, you're observing a (near) endless coinflip of tails. In real life, you don't get a few million tails in a row, but did I mention the coin is unfair? It's 'normal' here. But the crucial point is: The VM makes no guarantees about that coin flip at all - a VM that flips heads every time (thus having yield()
return quickly) is just as good, will pass the TCK, etcetera.
Thus: If ever the coin flip matters to how your code runs, you've messed up.
And you've done so here: worker-thread (the thread, not the object) reads its copy (which is false and remains false), and main-thread sets its copy of workerthread's (the object, not the thread)'s done flag to true. 1 field, but 2 cached copies, and now we're waiting for a coinflip of heads before that worker-thread ever manages to see what main-thread did.
Fortunately, we can force the VM to not flip that coin, and the route to do so is to establish a comes-before relationship.
The java memory model has written down a series of rules which establish that the VM will then acknowledge that 'event A happened before event B', and will guarantee that anything A did will be visible to B. No coin flip - B's copy will necessarily reflect what A did.
There's a long list but the important ones are:
imperative: Within a single thread, any statement that runs before another came-before that other. This is the 'duh, obviously' one: In
{ foo(); bar(); }
, anything foo does is visible to bar, because same thread.synchronized: Whenever a thread exits a synchronize-on-object-X block, that 'happens-before' any thread entering a synchronize-on-object-X block, if the thread entering does so afterwards.
volatile:
volatile
is a keyword you can put on a field. This is a bit trickier; volatile is defined in terms of CB/CA too, but it's a little easier to consider that any writing to volatile variables forces the coin to flip heads, writing out the update to every thread's copy. That makes volatile seem amazing, but it comes at quite a cost: volatile is rather slow, and not quite as useful as you might initially think, because you can't use it to set up atomic operations.Thread start: Whenever you start a thread, anything the thread that starts the new thread did before calling .start() is visible to the new thread immediately.
Of course, if some method internally synchronizes on things, by combining the synchronized rule and the imperative rule, then that method effectively also serves as a comes-before-establishing factor. You should use this - a bunch of JDK methods are defined to do so!
So, toss the synchronized blocks back in, thus establishing CB/CA between main-thread writing the done flag and worker-thread reading it, and the code works (and will in fact work on every JVM, regardless of OS, CPU, phase of the moon, or VM vendor). Without it, this code can do whatever it wants. Exit, or not, or exit after 4 hours, or exit only when your winamp switches songs. All's fair then, because you wrote code that depends on the result of a coin flip, so it's on you. Alternatively, mark the field 'volatile', that'll do it too.
So, how do you write multicore java code if it's this much of a minefield??
The true answer is: You mostly don't. It's too complicated. Instead, you do this:
- isolate: If no thread interacts with any other at all (nothing reads/writes fields except stuff entirely local to that thread's goingson), then trivially all the coin flips in the world aren't going to change anything, so do that. Set up the thread properly before you start it, let the thread run to its end, and have it communicate the thing it produced (if you need a return value at all) via a safe channel, and don't worry about it.
- streamline comms: Instead of communicating via fields (here your threads 'communicate'; main communicates to worker in the form of that boolean), communicate via a channel that is designed for concurrent control: Use a DB (thread A writes to DB, thread B also does so and the same tables and rows as A; DBs have facilities to manage this), or a message queue. This can be a full blown library like rabbitMQ, or a collection type from
java.util.concurrent
, such asBlockingQueue
. These have all solved the CB/CA issues for you. - rely on a framework: A web framework has many threads and will call your 'web handler' code on one appropriately. The handlers chat via DB, the web framework takes care of all the threading: All your CPU cores are zooming along and you never need to worry about any coinflips. You can also use the framework at the opposite end and use e.g. fork/join or the concept of stream->map->filter->collect (a.k.a. MapReduce).
*) It doesn't really, I'm giving you a mental model of how to think about it so that you won't write this bug. The point is, it MAY make a clone.
java synchronizing access to different critical sections
What you need is an exclusive lock on criticalMethod
and shareable locks on methods method1
and method2
. The simplest way to achieve this is to use java.util.concurrent.locks.ReentrantReadWriteLock
as below:
public class CriticalSections {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public void mainMethod(boolean b) {
if (b) {
method1();
} else {
criticalMethod();
method2();
}
}
private void criticalMethod() {
Lock writeLock = lock.writeLock();
writeLock.lock();
try {
System.out.println("in criticalMethod");
} finally {
writeLock.unlock();
}
}
private void method1() {
Lock readLock = lock.readLock();
readLock.lock();
try {
System.out.println("in method1");
} finally {
readLock.unlock();
}
}
private void method2() {
Lock readLock = lock.readLock();
readLock.lock();
try {
System.out.println("in method2");
} finally {
readLock.unlock();
}
}
}
If you're worried about performance, you can also take a look at java.util.concurrent.locks.StampedLock
(Java 8+).
synchronization : Threads execute two critical sections in same order
As I understand Critical Section #2 MUST be executed in the same order as Critical Section #1
If thread T1 executes block1 before thread T2, then T1 should execute block2 before T2. There are more than two threads.
Then a Queue might be used to ensure the order of execution.
private Object lock = new Object();
private Queue<Thread> threadQueue = new ArrayDeque<>();
// https://stackoverflow.com/questions/32353283/synchronization-threads-execute-two-critical-sections-in-same-order
public void executeCriticalSectionsInOrder() throws InterruptedException {
// Critical Section #1
synchronized (lock){
// synchronized code #1
// Add self to queue
threadQueue.add(Thread.currentThread());
}
// {lot of code where synchronization not necessary}
// Critical Section #2
synchronized (lock) {
//All the threads that executed block1 before this thread should have already executed this block.
// Wait turn
Thread t = threadQueue.element(); // Do not remove until it is self
while (t != Thread.currentThread()) {
lock.wait();
// After sleep try again
t = threadQueue.element();
}
// Verified own turn. Update status
threadQueue.remove();
// synchronized code #2
lock.notifyAll(); // Awake any waiting thread after exiting section.
}
However If one thread dies/exits without removing itself from the queue, then following threads will be blocked indefinetely. Maybe add a finally block to do the housekeeping?
Note: In Nicholas Robinson's answer a position order was suggested instead of a queue, which seems slightly more efficient.
Java - Synchronized block works differently than method
Per the JLS 8.4.3.6. synchronized Methods:
A synchronized method acquires a monitor (§17.1) before it executes.
For a class (static) method, the monitor associated with the Class object for the method's class is used.
For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
In the synchronized (getClass())
block you synchronize on the Class
object, thus all instances of ThreadSynchronous
are serialized.
When you make the instance method synchronized
, you are synchronizing only on that instance (the this
reference).
Avoid synchronized(this) in Java?
I'll cover each point separately.
Some evil code may steal your lock (very popular this one, also has an
"accidentally" variant)I'm more worried about accidentally. What it amounts to is that this use of
this
is part of your class' exposed interface, and should be documented. Sometimes the ability of other code to use your lock is desired. This is true of things likeCollections.synchronizedMap
(see the javadoc).All synchronized methods within the same class use the exact same
lock, which reduces throughputThis is overly simplistic thinking; just getting rid of
synchronized(this)
won't solve the problem. Proper synchronization for throughput will take more thought.You are (unnecessarily) exposing too much information
This is a variant of #1. Use of
synchronized(this)
is part of your interface. If you don't want/need this exposed, don't do it.
Related Topics
Scheduledexecutorservice Exception Handling
Totally Confused with Java.Exe
Soap Request to Webservice with Java
Java String.Indexof and Empty Strings
What Does an Integer That Has Zero in Front of It Mean and How to Print It
Preparedstatement Syntax Error
Method Calls Inside a Java Class Return an "Identifier Expected After This Token" Error
Noclassdeffounderror While Trying to Run My Jar with Java.Exe -Jar...What's Wrong
Can an Interface Extend Multiple Interfaces in Java
Minimum Spring Version Compatible with Java 11
Java.Net.Connectexception :Connection Timed Out: Connect
Does the Preparedstatement Avoid SQL Injection