Related
I am trying to wrap my head around thread safety in java (or in general). I have this class (which I hope complies with the definition of a POJO) which also needs to be compatible with JPA providers:
public class SomeClass {
private Object timestampLock = new Object();
// are "volatile"s necessary?
private volatile java.sql.Timestamp timestamp;
private volatile String timestampTimeZoneName;
private volatile BigDecimal someValue;
public ZonedDateTime getTimestamp() {
// is synchronisation necessary here? is this the correct usage?
synchronized (timestampLock) {
return ZonedDateTime.ofInstant(timestamp.toInstant(), ZoneId.of(timestampTimeZoneName));
}
}
public void setTimestamp(ZonedDateTime dateTime) {
// is this the correct usage?
synchronized (timestampLock) {
this.timestamp = java.sql.Timestamp.from(dateTime.toInstant());
this.timestampTimeZoneName = dateTime.getZone().getId();
}
}
// is synchronisation required?
public BigDecimal getSomeValue() {
return someValue;
}
// is synchronisation required?
public void setSomeValue(BigDecimal val) {
someValue = val;
}
}
As stated in the commented rows in the code, is it necessary to define timestamp and timestampTimeZoneName as volatile and are the synchronized blocks used as they should be? Or should I use only the synchronized blocks and not define timestamp and timestampTimeZoneName as volatile? A timestampTimeZoneName of a timestamp should not be erroneously matched with another timestamp's.
This link says
Reads and writes are atomic for all variables declared volatile
(including long and double variables)
Should I understand that accesses to someValue in this code through the setter/getter are thread safe thanks to volatile definitions? If so, is there a better (I do not know what "better" might mean here) way to accomplish this?
To determine if you need synchronized, try to imagine a place where you can have a context switch that would break your code.
In this case, if the context switch happens where I put the comment, then in getTimestamp() you're going to be reading different values from each timestamp type.
Also, although assignments are atomic, this expression java.sql.Timestamp.from(dateTime.toInstant()); certainly isn't, so you can get a context switch inbetween dateTime.toInstant() and the call to from. In short you definitely need the synchronized blocks.
synchronized (timestampLock) {
this.timestamp = java.sql.Timestamp.from(dateTime.toInstant());
//CONTEXT SWITCH HERE
this.timestampTimeZoneName = dateTime.getZone().getId();
}
synchronized (timestampLock) {
return ZonedDateTime.ofInstant(timestamp.toInstant(), ZoneId.of(timestampTimeZoneName));
}
In terms of volatile, I'm pretty sure they're required. You have to guarantee that each thread definitely is getting the most updated version of a variable.
This is the contract of volatile. And although it may be covered by the synchronized block, and volatile not actually necessary here, it's good to write anyway. If the synchronized block does the job of volatile already, the VM won't do the guarantee twice. This means volatile won't cost you any more, and it's a very good flashing light that says to the programmer: "I'M USED IN MULTIPLE THREADS".
For someValue: If there's no synchronized block here, then volatile is definitely necessary. If you call a set in one thread, the other thread has no queue that tells it that may have been updated outside of this thread. So it may use an old and cached value. The JIT can do a lot of funny optimizations if it assumes single thread. Ones that can simply break your program.
Now I'm not entirely certain if synchronized is required here. My guess is no. I would add it anyway to be safe though. Or you can let java worry about the synchronization and use http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html
Nothing new here, this is just a more explicit version of something #Cruncher already said:
You need synchronized whenever it is important for two or more fields in your program to be consistent with one another. Suppose you have two parallel lists, and your code depends on them both being the same length. That's called an invariant as in, the two lists are invariably the same length.
How can you write a method, append(x,y), that adds a new pair of values to the lists without temporarily breaking the invariant? You can't. The method must add one item to the first list, breaking the invariant, and then add the other item to the second list, fixing it again. There's no other way.
In a single-threaded program, that temporary broken state is no problem because no other method can possibly use the lists while append(x,y) is running. That's no longer true in a multithreaded program. In the worst case, append(x,y) could add x to the x list, and then the scheduler could suspend the thread at that exact moment to allow other threads to run. The CPUs could execute millions of instructions before append(x,y) gets to finish the job and make the lists right again. During all of that time, other threads would see the broken invariant, and possibly corrupt your data or crash the program as a result.
The fix is for append(x,y) to be synchronized on some object, and (this is the important part), for every other method that uses the lists to be synchronized on the same object. Since only one thread can be synchronized on a given object at a given time, it will not be possible for any other thread to see the lists in an inconsistent state.
So, if thread A calls append(x,y), and thread B tries to look at the lists "at the same time", will thread B see the what the lists looked like before or after thread A did its work? That's called a data race. And with only the synchronization that I have described so far, there's no way to know which thread will win. All we've done so far is to guarantee one particular invariant.
If it matters which thread wins the race, then that means that there is some higher-level invariant that also needs protection. You will have to add more synchronization to protect that one too. "Thread safety" -- two little words to name a subject that is both broad and deep.
Good Luck, and Have Fun!
// is synchronisation required?
public BigDecimal getSomeValue() {
return someValue;
}
// is synchronisation required?
public void setSomeValue(BigDecimal val) {
someValue = val;
}
I think Yes you are require to put the synchronization block because consider an example in which one thread is setting the value and at the same time other thread is trying to read from getter method, like here in the example you will see the syncronization block.So, if you take your variable inside the method then you must require the synchronization block.
For instance,
class Test{
static Map a = new ...
static Map b = new ...
public void process(){
...
a.put(...);
b.put(...);
}
}
Do I have to lock like this:
synchronized(a){
a.put();
}
synchronized(b){
b.put(b);
}
This seems to be awkward. Any other right way to do this? Thanks.
No, you need both operations in one synchronized block, otherwise another thread may see inconsistencies between the two maps.
One possible option would be using a synchronized method, or you could use some other private object or one of the maps as an monitor. Here is the synchronized method example:
static Map a = new ...
static Map b = new ...
public synchronized void process(){
...
a.put(...);
b.put(...);
}
}
You can use a dedicated object like
Object mapLock = new Object();
to synchronize on.
Or you can sync on a keeping in mind that even if you need an access to b you need to sync on a.
Synchronizing on this is not a good idea in general. I mean this is a bad habit and doing so may eventually result in bad performance or non-obvious deadlocks if not in this but other applications you make.
Avoid synchronized(this) in Java?
You can also consider using ReadWriteLock from concurrency package.
You do need to run both operations within one synchronized block. Worth noting that in your example, you've defined the maps statically while the process() method is an instance method. The synchronizing the method will mean that calls to that instance will be synchronized, but that calls to 2 different instances will not (as the lock used when applying the synchronized keyword to a method is effectively this). You could either make the process() method static, or use a synchronized(Test.class) {} block instead to ensure that there's no racing happening.
You will also need to be careful about how you expose the maps to clients - if you're offering them up as properties, then I would probably wrap them with Collections.unmodifiableMap() to ensure that nothing else can go and screw with them while you're not looking - however that doesn't entirely protect against clients having an "odd" time as they will still see changes happen in potentially unsafe ways. As such, I'd also probably declare the types as ConcurrentHashMap to make things a little safer (although there are still some dangerous operations such as sharing an Iterator between threads)
Could anyone explain what is the difference between these examples?
Example # 1.
public class Main {
private Object lock = new Object();
private MyClass myClass = new MyClass();
public void testMethod() {
// TODO Auto-generated method stub
synchronized (myClass) {
// TODO: modify myClass variable
}
}
}
Example # 2.
package com.test;
public class Main {
private MyClass myClass = new MyClass();
private Object lock = new Object();
public void testMethod() {
// TODO Auto-generated method stub
synchronized (lock) {
// TODO: modify myClass variable
}
}
}
What should I use as a monitor lock if I need to take care about synchronization when modifying the variable?
Assuming that Main is not intended to be a "leaky abstraction", here is minimal difference between the first and second examples.
It may be better to use an Object rather than some other class because an Object instance has no fields and is therefore smaller. And the Object-as-lock idiom makes it clear that the lock variable is intended to only ever used as a lock.
Having said that, there is a definite advantage in locking on an object that nothing else will ever see. The problem with a Main method synchronizing on a Main (e.g. this) is that other unrelated code could also be synchronizing on it for an unrelated purpose. By synchronizing on dedicated (private) lock object you avoid that possibility.
In response to the comment:
There is a MAJOR difference in the two cases. In the first you're locking the object that you want to manipulate. In the second you're locking some other object that has no obvious relationship to the object being manipulated. And the second case takes more space, since you must allocate the (otherwise unused) Object, rather than using the already-existing instance you're protecting.
I think you are making an INCORRECT assumption - that MyClass is the data structure that needs protecting. In fact, the Question doesn't say that. Indeed the way that the example is written implies that the lock is intended to protect the entire Main class ... not just a part of its state. And in that context, there IS an obvious connection ...
The only case where it would be better to lock the MyClass would be if the Main was a leaky abstraction that allowed other code to get hold of its myClass reference. That would be bad design, especially in a multi-threaded app.
Based on the revision history, I'm pretty sure that is not the OP's intention.
The statement synchronization is useful when changing variables of an object.
You are changing variables of myClass so you want to lock on myClass object. If you were to change something in lock then you want to lock on lock object.
In example #2 you are modifying myClass but locking on lock object which is nonsense.
In first case you lock on object that it known only within this method, so it is unlikely that anybody else will use the same object to lock on, so such lock is almost useless. Second variant makes much more sense for me.
At the same time, myClass variable is also known only within this method, so it is unlikely that other thread will access it, so probably lock is not necessary here at all. Need more complete example to say more.
In general, you want to lock on the "root" object of the data you're manipulating. If you're, eg, going to subtract a value from a field in object A and add that value to object B, you need to lock some object that is somehow common (at least by convention) between A and B, possibly the "owner" object of the two. This is because you're doing the lock to maintain a "contract" of consistency between separate pieces of data -- the object locked must be common to and conceptually encompassing of the entire set of data that must be kept consistent.
The simple case, of course, is when you're modifying field A and field B in the same object, in which case locking that object is the obvious choice.
A little less obvious is when you're dealing with static data belonging to a single class. In that case you generally want to lock the class.
A separate "monitor" object -- created only to serve as a lockable entity -- is rarely needed in Java, but might apply to, say, elements of two parallel arrays, where you want to maintain consistency between element N of the two arrays. In that case, something like a 3rd array of monitor objects might be appropriate.
(Note that this is all just a "quick hack" at laying out some rules. There are many subtleties that one can run into, especially when attempting to allow the maximum of concurrent access to heavily-accessed data. But such cases are rare outside of high-performance computing.)
Whatever you choose, it's critical that the choice be consistent across all references to the protected data. You don't want to lock object A in one case and object B in another, when referencing/modifying the same data. (And PLEASE don't fall into the trap of thinking you can lock an arbitrary instance of Class A and that will somehow serve to lock another instance of Class A. That's a classical beginner's mistake.)
In your above example you'd generally want to lock the created object, assuming the consistency you're assuring is all internal to that object. But note that in this particular example, unless the constructor for MyClass somehow lets the object address "escape", there is no need to lock at all, since there is no way that another thread can get the address of the new object.
The difference are the class of the lock and its scope
- Both topics are pretty much orthogonal with synchronization
objects with different classes may have different sizes
objects in different scopes may be available in different contexts
Basically both will behave the same in relation to synchronization
Both examples are not good syncronisation practise.
The lock Object should be placed in MyClass as private field.
From Sun's tutorial:
Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods. (An important exception: final fields, which cannot be modified after the object is constructed, can be safely read through non-synchronized methods, once the object is constructed) This strategy is effective, but can present problems with liveness, as we'll see later in this lesson.
Q1. Is the above statements mean that if an object of a class is going to be shared among multiple threads, then all instance methods of that class (except getters of final fields) should be made synchronized, since instance methods process instance variables?
In order to understand concurrency in Java, I recommend the invaluable Java Concurrency in Practice.
In response to your specific question, although synchronizing all methods is a quick-and-dirty way to accomplish thread safety, it does not scale well at all. Consider the much maligned Vector class. Every method is synchronized, and it works terribly, because iteration is still not thread safe.
No. It means that synchronized methods are a way to achieve thread safety, but they're not the only way and, by themselves, they don't guarantee complete safety in all situations.
Not necessarily. You can synchronize (e.g. place a lock on dedicated object) part of the method where you access object's variables, for example. In other cases, you may delegate job to some inner object(s) which already handles synchronization issues.
There are lots of choices, it all depends on the algorithm you're implementing. Although, 'synchronized' keywords is usually the simplest one.
edit
There is no comprehensive tutorial on that, each situation is unique. Learning it is like learning a foreign language: never ends :)
But there are certainly helpful resources. In particular, there is a series of interesting articles on Heinz Kabutz's website.
http://www.javaspecialists.eu/archive/Issue152.html
(see the full list on the page)
If other people have any links I'd be interested to see also. I find the whole topic to be quite confusing (and, probably, most difficult part of core java), especially since new concurrency mechanisms were introduced in java 5.
Have fun!
In the most general form yes.
Immutable objects need not be synchronized.
Also, you can use individual monitors/locks for the mutable instance variables (or groups there of) which will help with liveliness. As well as only synchronize the portions where data is changed, rather than the entire method.
synchronized methodName vs synchronized( object )
That's correct, and is one alternative. I think it would be more efficient to synchronize access to that object only instead synchronize all it's methods.
While the difference may be subtle, it would be useful if you use that same object in a single thread
ie ( using synchronized keyword on the method )
class SomeClass {
private int clickCount = 0;
public synchronized void click(){
clickCount++;
}
}
When a class is defined like this, only one thread at a time may invoke the click method.
What happens if this method is invoked too frequently in a single threaded app? You'll spend some extra time checking if that thread can get the object lock when it is not needed.
class Main {
public static void main( String [] args ) {
SomeClass someObject = new SomeClass();
for( int i = 0 ; i < Integer.MAX_VALUE ; i++ ) {
someObject.click();
}
}
}
In this case, the check to see if the thread can lock the object will be invoked unnecessarily Integer.MAX_VALUE ( 2 147 483 647 ) times.
So removing the synchronized keyword in this situation will run much faster.
So, how would you do that in a multithread application?
You just synchronize the object:
synchronized ( someObject ) {
someObject.click();
}
Vector vs ArrayList
As an additional note, this usage ( syncrhonized methodName vs. syncrhonized( object ) ) is, by the way, one of the reasons why java.util.Vector is now replaced by java.util.ArrayList. Many of the Vector methods are synchronized.
Most of the times a list is used in a single threaded app or piece of code ( ie code inside jsp/servlets is executed in a single thread ), and the extra synchronization of Vector doesn't help to performance.
Same goes for Hashtable being replaced by HashMap
In fact getters a should be synchronized too or fields are to be made volatile. That is because when you get some value, you're probably interested in a most recent version of the value. You see, synchronized block semantics provides not only atomicity of execution (e.g. it guarantees that only one thread executes this block at one time), but also a visibility. It means that when thread enters synchronized block it invalidates its local cache and when it goes out it dumps any variables that have been modified back to main memory. volatile variables has the same visibility semantics.
No. Even getters have to be synchronized, except when they access only final fields. The reason is, that, for example, when accessing a long value, there is a tiny change that another thread currently writes it, and you read it while just the first 4 bytes have been written while the other 4 bytes remain the old value.
Yes, that's correct. All methods that modify data or access data that may be modified by a different thread need to be synchronized on the same monitor.
The easy way is to mark the methods as synchronized. If these are long-running methods, you may want to only synchronize that parts that the the reading/writing. In this case you would definie the monitor, along with wait() and notify().
The simple answer is yes.
If an object of the class is going to be shared by multiple threads, you need to syncronize the getters and setters to prevent data inconsistency.
If all the threads would have seperate copy of object, then there is no need to syncronize the methods. If your instance methods are more than mere set and get, you must analyze the threat of threads waiting for a long running getter/setter to finish.
You could use synchronized methods, synchronized blocks, concurrency tools such as Semaphore or if you really want to get down and dirty you could use Atomic References. Other options include declaring member variables as volatile and using classes like AtomicInteger instead of Integer.
It all depends on the situation, but there are a wide range of concurrency tools available - these are just some of them.
Synchronization can result in hold-wait deadlock where two threads each have the lock of an object, and are trying to acquire the lock of the other thread's object.
Synchronization must also be global for a class, and an easy mistake to make is to forget to synchronize a method. When a thread holds the lock for an object, other threads can still access non synchronized methods of that object.
In Java, the idiomatic way to declare critical sections in the code is the following:
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
Almost all blocks synchronize on this, but is there a particular reason for this? Are there other possibilities? Are there any best practices on what object to synchronize on? (such as private instances of Object?)
As earlier answerers have noted, it is best practice to synchronize on an object of limited scope (in other words, pick the most restrictive scope you can get away with, and use that.) In particular, synchronizing on this is a bad idea, unless you intend to allow the users of your class to gain the lock.
A particularly ugly case arises, though, if you choose to synchronize on a java.lang.String. Strings can be (and in practice almost always are) interned. That means that each string of equal content - in the ENTIRE JVM - turns out to be the same string behind the scenes. That means that if you synchronize on any String, another (completely disparate) code section that also locks on a String with the same content, will actually lock your code as well.
I was once troubleshooting a deadlock in a production system and (very painfully) tracked the deadlock to two completely disparate open source packages that each synchronized on an instance of String whose contents were both "LOCK".
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
I try to avoid synchronizing on this because that would allow everybody from the outside who had a reference to that object to block my synchronization. Instead, I create a local synchronization object:
public class Foo {
private final Object syncObject = new Object();
…
}
Now I can use that object for synchronization without fear of anybody “stealing” the lock.
Just to highlight that there are also ReadWriteLocks available in Java, found as java.util.concurrent.locks.ReadWriteLock.
In most of my usage, I seperate my locking as 'for reading' and 'for updates'. If you simply use a synchronized keyword, all reads to the same method/code block will be 'queued'. Only one thread can access the block at one time.
In most cases, you never have to worry about concurrency issues if you are simply doing reading. It is when you are doing writing that you worry about concurrent updates (resulting in lost of data), or reading during a write (partial updates), that you have to worry about.
Therefore a read/write lock makes more sense to me during multi-threaded programming.
You'll want to synchronize on an object that can serve as a Mutex. If the current instance (the this reference) is suitable (not a Singleton, for instance), you may use it, as in Java any Object may serve as the Mutex.
In other occasions, you may want to share a Mutex between several classes, if instances of these classes may all need access to the same resources.
It depends a lot on the environment you're working in and the type of system you're building. In most Java EE applications I've seen, there's actually no real need for synchronization...
Personally, I think the answers which insist that it is never or only rarely correct to sync on this are misguided. I think it depends on your API. If your class is a threadsafe implementation and you so document it, then you should use this. If the synchronization is not to make each instance of the class as a whole threadsafe in the invocation of it's public methods, then you should use a private internal object. Reusable library components often fall into the former category - you must think carefully before you disallow the user to wrap your API in external synchronization.
In the former case, using this allows multiple methods to be invoked in an atomic manner. One example is PrintWriter, where you may want to output multiple lines (say a stack trace to the console/logger) and guarantee they appear together - in this case the fact that it hides the sync object internally is a real pain. Another such example are the synchronized collection wrappers - there you must synchronize on the collection object itself in order to iterate; since iteration consists of multiple method invocations you cannot protect it totally internally.
In the latter case, I use a plain object:
private Object mutex=new Object();
However, having seen many JVM dumps and stack traces that say a lock is "an instance of java.lang.Object()" I have to say that using an inner class might often be more helpful, as others have suggested.
Anyway, that's my two bits worth.
Edit: One other thing, when synchronizing on this I prefer to sync the methods, and keep the methods very granular. I think it's clearer and more concise.
Synchronization in Java often involves synchronizing operations on the same instance. Synchronizing on this then is very idiomatic since this is a shared reference that is automatically available between different instance methods (or sections of) in a class.
Using another reference specifically for locking, by declaring and initializing a private field Object lock = new Object() for example, is something I never needed or used. I think it is only useful when you need external synchronization on two or more unsynchronized resources inside an object, although I would always try to refactor such a situation into a simpler form.
Anyway, implicit (synchronized method) or explicit synchronized(this) is used a lot, also in the Java libraries. It is a good idiom and, if applicable, should always be your first choice.
On what you synchronize depends on what other threads that might potentially get into conflict with this method call can synchronize.
If this is an object that is used by only one thread and we are accessing a mutable object which is shared between threads, a good candidate is to synchronize over that object - synchronizing on this has no point since another thread that modifies that shared object might not even know this, but does know that object.
On the other hand synchronizing over this makes sense if many threads call methods of this object at the same time, for instance if we are in a singleton.
Note that a syncronized method is often not the best option, since we hold a lock the whole time the method runs. If it contains timeconsuming but thread safe parts, and a not so time consuming thread-unsafe part, synchronizing over the method is very wrong.
Almost all blocks synchronize on this, but is there a particular reason for this? Are there other possibilities?
This declaration synchronizes entire method.
private synchronized void doSomething() {
This declaration synchronized a part of code block instead of entire method.
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
From oracle documentation page
making these methods synchronized has two effects:
First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Are there other possibilities? Are there any best practices on what object to synchronize on? (such as private instances of Object?)
There are many possibilities and alternatives to synchronization. You can make your code thread safe by using high level concurrency APIs( available since JDK 1.5 release)
Lock objects
Executors
Concurrent collections
Atomic variables
ThreadLocalRandom
Refer to below SE questions for more details:
Synchronization vs Lock
Avoid synchronized(this) in Java?
the Best Practices is to create an object solely to provide the lock:
private final Object lock = new Object();
private void doSomething() {
// thread-safe code
synchronized(lock) {
// thread-unsafe code
}
// thread-safe code
}
By doing this you are safe, that no calling code can ever deadlock your method by an unintentional synchronized(yourObject) line.
(Credits to #jared and #yuval-adam who explained this in more details above.)
My guess is that the popularity of using this in tutorials came from early Sun javadoc: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Synchronization includes 3 parts: Atomicity, Visibility and Ordering
Synchronized block is very coarse level of synchronization. It enforces visibility and ordering just as what you expected. But for atomicity, it does not provide much protection. Atomicity requires global knowledge of the program rather than local knowledge. (And that makes multi-threading programming very hard)
Let's say we have a class Account having method deposit and withdraw. They are both synchronized based on a private lock like this:
class Account {
private Object lock = new Object();
void withdraw(int amount) {
synchronized(lock) {
// ...
}
}
void deposit(int amount) {
synchronized(lock) {
// ...
}
}
}
Considering we need to implement a higher-level class which handles transfer, like this:
class AccountManager {
void transfer(Account fromAcc, Account toAcc, int amount) {
if (fromAcc.getBalance() > amount) {
fromAcc.setBalance(fromAcc.getBalance() - amount);
toAcc.setBalance(toAcc.getBalance + amount);
}
}
}
Assuming we have 2 accounts now,
Account john;
Account marry;
If the Account.deposit() and Account.withdraw() are locked with internal lock only. That will cause problem when we have 2 threads working:
// Some thread
void threadA() {
john.withdraw(500);
}
// Another thread
void threadB() {
accountManager.transfer(john, marry, 100);
}
Because it is possible for both threadA and threadB run at the same time. And thread B finishes the conditional check, thread A withdraws, and thread B withdraws again. This means we can withdraw $100 from John even if his account has no enough money. This will break atomicity.
You may propose that: why not adding withdraw() and deposit() to AccountManager then? But under this proposal, we need to create a multi-thread safe Map which maps from different accounts to their locks. We need to delete the lock after execution (otherwise will leak memory). And we also need to ensure no other one accesses the Account.withdraw() directly. This will introduce a lots of subtle bugs.
The correct and most idiomatic way is to expose the lock in the Account. And let the AccountManager to use the lock. But in this case, why not just use the object itself then?
class Account {
synchronized void withdraw(int amount) {
// ...
}
synchronized void deposit(int amount) {
// ...
}
}
class AccountManager {
void transfer(Account fromAcc, Account toAcc, int amount) {
// Ensure locking order to prevent deadlock
Account firstLock = fromAcc.hashCode() < toAcc.hashCode() ? fromAcc : toAcc;
Account secondLock = fromAcc.hashCode() < toAcc.hashCode() ? toAcc : fromAcc;
synchronized(firstLock) {
synchronized(secondLock) {
if (fromAcc.getBalance() > amount) {
fromAcc.setBalance(fromAcc.getBalance() - amount);
toAcc.setBalance(toAcc.getBalance + amount);
}
}
}
}
}
To conclude in simple English, private lock does not work for slightly more complicated multi-threaded program.