Assume we have to undertake a transfer between any 2 accounts(among hunders out there) as part of a transaction.
And there would be multiple similar transactions running concurrently in a typical multi-threaded environment.
Usual convention would be as below(maintaining the lock order as per a pre-designed convention):
lock account A
lock account B
transfer(A,B)
release B
release A
Is there any way to attempt the locks and release as an atomic operation?
Yes there is: you need to lock the locks under a lock. In other words, you need to create a lock hierarchy. But this solution is not very efficient because it decreases lock granularity.
It looks like in your case it would be sufficient to always take locks in the same order. For example always lock user with lesser ID first.
Transaction is atomic by ACID definition (A - for atomicity). Isolation (at least READ_COMMITED one) guarantee that other transaction that may occur for account A at the same time will wait while previous started transaction will be finished. So actually, you don't need to lock them explicitly as they will lock by internal implementation (database for example) and that locks will be more efficient as they can use optimistic locking techniques.
But this is only true if they all participating in one transactional context (like in JTA environment for example). In such environment you could just start transaction in the beginning of transfer method and no need for locking Account A and Account B.
In case, that they are not in the same transactional context, you can introduce some another locking object but this will significantly reduce performance as threads will be locked even though one is working with accounts A and B and another one with accounts C and D. There are techniques in how to avoid this situation (see ConcurentHashMap for example, where
locks are on baskets - and not on the whole object).
But with your particular example answer could only be some general thoughts as example is to short to examine more. I think variant with locking account A and account B in particular order (should be very care with that - as this could lead to potential deadlocks. And assuming there is not just transfer method that could work with them - it is really high risky) is normal for given situation.
You can try to use the following code.
Note: it only work for two locks and I'm unsure how to make it scale to more locks.
The idea is that you take the first lock and you try to take the second one.
If it fails, we know that 1 lock is free right now, but the other is busy.
Thus we release the first lock and you invert them, so we will lock on the one that was busy and try to take the one that (WAS!) free, if it is still free.
Rinse and repeat.
There is a statistically impossibility that this code will go in StackOverflow,
I think handling it and giving an error is better than making it loop, since it would be a signal that something somewhere is going very wrong.
public static void takeBoth(ReentrantLock l1,ReentrantLock l2) {
l1.lock();
if(l2.tryLock()) {return;}
l1.unlock();
try{takeBoth(l2,l1);}
catch(StackOverflowError e) {throw new Error("??");}
}
public static void releaseBoth(ReentrantLock l1,ReentrantLock l2){
if(!l1.isHeldByCurrentThread()) {l1.unlock();}//this will fail: IllegarMonitorState exception
l2.unlock();//this may fail, in that case we did not touch l1.
l1.unlock();
}
Related
After reading a little bit about the java memory model and synchronization, a few questions came up:
Even if Thread 1 synchronizes the writes, then although the effect of the writes will be flushed to main memory, Thread 2 will still not see them because the read came from level 1 cache. So synchronizing writes only prevents collisions on writes. (Java thread-safe write-only hashmap)
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads. (https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html)
A third website (I can't find it again, sorry) said that every change to any object - it doesn't care where the reference comes from - will be flushed to memory when the method leaves the synchronized block and establishes a happens-before situation.
My questions are:
What is really flushed back to memory by exiting the synchronized block? (As some websites also said that only the object whose lock has been aquired will be flushed back.)
What does happens-before-relaitonship mean in this case? And what will be re-read from memory on entering the block, what not?
How does a lock achieve this functionality (from https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html):
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in section 17.4 of The Java™ Language Specification:
A successful lock operation has the same memory synchronization effects as a successful Lock action.
A successful unlock operation has the same memory synchronization effects as a successful Unlock action.
Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.
If my assumtion that everything will be re-read and flushed is correct, this is achieved by using synchronized-block in the lock- and unlock-functions (which are mostly also necessary), right? And if it's wrong, how can this functionality be achieved?
Thank you in advance!
The happens-before-relationship is the fundamental thing you have to understand, as the formal specification operates in terms of these. Terms like “flushing” are technical details that may help you understanding them, or misguide you in the worst case.
If a thread performs action A within a synchronized(object1) { … }, followed by a thread performing action B within a synchronized(object1) { … }, assuming that object1 refers to the same object, there is a happens-before-relationship between A and B and these actions are safe regarding accessing shared mutable data (assuming, no one else modifies this data).
But this is a directed relationship, i.e. B can safely access the data modified by A. But when seeing two synchronized(object1) { … } blocks, being sure that object1 is the same object, you still need to know whether A was executed before B or B was executed before A, to know the direction of the happens-before-relationship. For ordinary object oriented code, this usually works naturally, as each action will operate on whatever previous state of the object it finds.
Speaking of flushing, leaving a synchronized block causes flushing of all written data and entering a synchronized block causes rereading of all mutable data, but without the mutual exclusion guaranty of a synchronized on the same instance, there is no control over which happens before the other. Even worse, you can not use the shared data to detect the situation, as without blocking the other thread, it can still inconsistently modify the data you’re operating on.
Since synchronizing on different objects can’t establish a valid happens-before relationship, the JVM’s optimizer is not required to maintain the global flush effect. Most notably, today’s JVMs will remove synchronization, if Escape Analysis has proven that the object is never seen by other threads.
So you can use synchronizing on an object to guard access to data stored somewhere else, i.e not in that object, but it still requires consistent synchronizing on the same object instance for all access to the same shared data, which complicates the program logic, compared to simply synchronizing on the same object containing the guarded data.
volatile variables, like used by Locks internally, also have a global flush effect, if threads are reading and writing the same volatile variable, and use the value to form a correct program logic. This is trickier than with synchronized blocks, as there is no mutual exclusion of code execution, or well, you could see it as having a mutual exclusion limited to a single read, write, or cas operation.
There is no flush per-se, it's just easier to think that way (easier to draw too); that's why there are lots of resources online that refer to flush to main memory (RAM assuming), but in reality it does not happen that often. What really happens is that a drain is performed of the load and/or store buffers to L1 cache (L2 in case of IBM) and it's up to the cache coherence protocol to sync data from there; or to put it differently caches are smart enough to talk to each other (via a BUS) and not fetch data from main memory all the time.
This is a complicated subject (disclaimer: even though I try to do a lot of reading on this, a lot of tests when I have time, I absolutely do not understand it in full glory), it's about potential compiler/cpu/etc re-orderings (program order is never respected), it's about flushes of the buffers, about memory barriers, release/acquire semantics... I don't think that your question is answerable without a phD report; that's why there are higher layers in the JLS called - "happens-before".
Understanding at least a small portion of the above, you would understand that your questions (at least first two), make very little sense.
What is really flushed back to memory by exiting the synchronized block
Probably nothing at all - caches "talk" to each other to sync data; I can only think of two other cases: when you first time read some data and when a thread dies - all written data will be flushed to main memory(but I'm not sure).
What does happens-before-relaitonship mean in this case? And what will be re-read from memory on entering the block, what not?
Really, the same sentence as above.
How does a lock achieve this functionality
Usually by introducing memory barriers; just like volatiles do.
While going through Java Concurrency in Practice book, came across this piece of code where "fromAccount" and ""toAccount" objects are locked one after the other to prevent dynamic lock order deadlock.
public void transferMoney(Account fromAccount,Account toAccount) {
**synchronized (fromAccount) {**
**synchronized (toAccount) {**
........
}
}
}
I am confused as to why this lock ordering is needed at all.If we just wanted to make sure that both the objects are locked at the same time then wouldn't you get the same effect if there was just a regular synchronization block inside which fromAccount and toAccount objects are accessed. I am sure that I am missing some fundamental concept here. Thank you for your help.
public void transferMoney(Account fromAccount,Account toAccount) {
synchronized (this) {
fromAccount.someMethod();
toAccount.someMethod();
}
}
Your alternative to the lock-ordering example is what you want to avoid: having a central lock that everything is using, because then you don't get concurrent transfers, everything waits for that one lock and only one transfer can proceed at a time. It's not clear what this is or what its scope can possibly be, but if there are multiple instances of this transfer service then locking doesn't do any good, because one transfer involving one account can go through one instance while another transfer involving that same account can go through another. Therefore it seems like there can only be one of them, which diminishes your concurrency to one transfer at a time. You won't deadlock, but you won't process a lot of transfers quickly either.
The idea behind this toy example (which you shouldn't mistake for anything like how anybody would transfer money) is it's trying to get better concurrency by locking on the individual accounts involved in the transfer, because for a lot of transfers the accounts involved aren't involved in other concurrent transfers and you'd like to be able to process them concurrently and maximize your concurrency by minimizing the scope of the locking going on to the individual accounts. But this scheme runs into trouble if some account is involved in multiple concurrent transfers and the locks are acquired in a different order for some transfers.
First, it should be noted that the example you have brought (based on your comment, it's page 208, listing 10.2) is a bad example - one that ends in a deadlock. The objects are not locked one after the other to prevent dynamic lock order deadlock, they are an example of where dynamic lock order will happen!
Now, you are suggesting locking on this, but what is this this anyway, and what is the scope of locking?
It's clear that the same object has to be used for all operations - withdraw, deposit, transfer. If separate objects are used for them, then one thread could do a deposit on account A, while another thread transfers from account A to account B, and they won't be using the same lock so the balance will be compromised. So the lock object for all accesses to the same account should be the same one.
As Nathan Hughes explained, one needs to localize the locking. We can't use one central lock object for all the accounts, or we'll have them all waiting for each other despite not actually working on the same resources. So using a central locking object is also out of the question.
So it appears that we need to localize the locks so that each account's balance will have its own lock, so as to allow parallel operations between unrelated accounts, but that this lock has to be used for all operations - withdraw, deposit and transfer.
And here comes the problem - when it's just withdraw or deposit, you are operating on just one account, and so you need to just lock that account. But when you transfer, you have two objects involved. So you need to have both their balances locked in case there are other threads that want to operate on either.
Any object that holds a single lock for two or more accounts will break one of the two points above. Either it won't be used for all operations, or it will not be localized enough.
This is why they are attempting to lock the two locks one after another. Their solution was to make the Account object itself the lock for the account - which fulfils both the "all operations" condition and the "locality" condition. But still we need to make sure we have the locks for both accounts before we can transfer the money.
But again, this source is an example of a deadlock prone code. This is because one thread may want to transfer from account A to account B, while another will want to transfer from account B to account A. In that case, the first one locks the A account, the second locks the B account, and then they are deadlocked because they have performed the locking in opposite order.
The basic fundamental here is to avoid race condition. In your case if there will be another method in any other class who is also doing transfer money to toAccount then incorrect amount may get update in the toAccount. e.g. There are 2 classes which performs money transfer.
One class has a method:
public void transferMoney(Account fromAccount,Account toAccount) {
synchronized (this) {
fromAccount.someMethod();
toAccount.someMethod();
}
}
and other class contains:
public void transferMoneyNow(Account fromAccount1,Account toAccount) {
synchronized (this) {
fromAccount1.someMethod();
toAccount.someMethod();
}
}
If both method takes place at the same time, due to race condition incorrect amount may get update in toAccount.
I am learning multithreading, and I have a little question.
When I am sharing some variable between threads (ArrayList, or something other like double, float), should it be lcoked by the same object in read/write? I mean, when 1 thread is setting variable value, can another read at same time withoud any problems? Or should it be locked by same object, and force thread to wait with reading, until its changed by another thread?
All access to shared state must be guarded by the same lock, both reads and writes. A read operation must wait for the write operation to release the lock.
As a special case, if all you would to inside your synchronized blocks amounts to exactly one read or write operation, then you may dispense with the synchronized block and mark the variable as volatile.
Short: It depends.
Longer:
There is many "correct answer" for each different scenarios. (and that makes programming fun)
Do the value to be read have to be "latest"?
Do the value to be written have let all reader known?
Should I take care any race-condition if two threads write?
Will there be any issue if old/previous value being read?
What is the correct behaviour?
Do it really need it to be correct ? (yes, sometime you don't care for good)
tl;dr
For example, not all threaded programming need "always correct"
sometime you tradeoff correctness with performance (e.g. log or progress counter)
sometime reading old value is just fine
sometime you need eventually correct (e.g. in map-reduce, nobody nor synchronized is right until all done)
in some cases, correct is mandatory for every moment (e.g. your bank account balance)
in write-once, read-only it doesn't matter.
sometime threads in groups with complex cases.
sometime many small, independent lock run faster, but sometime flat global lock is faster
and many many other possible cases
Here is my suggestion: If you are learning, you should thing "why should I need a lock?" and "why a lock can help in DIFFERENT cases?" (not just the given sample from textbook), "will if fail or what could happen if a lock is missing?"
If all threads are reading, you do not need to synchronize.
If one or more threads are reading and one or more are writing you will need to synchronize somehow. If the collection is small you can use synchronized. You can either add a synchronized block around the accesses to the collection, synchronized the methods that access the collection or use a concurrent threadsafe collection (for example, Vector).
If you have a large collection and you want to allow shared reading but exclusive writing you need to use a ReadWriteLock. See here for the JavaDoc and an exact description of what you want with examples:
ReentrantReadWriteLock
Note that this question is pretty common and there are plenty of similar examples on this site.
Lets say I have a Set and another Queue. I want to check in the set if it contains(Element) and if not add(element) to the queue. I want to do the two steps atomically.
One obvious way is to use synchronized blocks or Lock.lock()/unlock() methods. Under thread contention , these will cause context switches. Is there any simple design strategy for achieving this in a non-blocking manner ? may be using some Atomic constructs ?
I don't think you can rely on any mechanism, except the ones you pointed out yourself, simply because you're operating on two structures.
There's decent support for concurrent/atomic operations on one data structure (like "put if not exists" in a ConcurrentHashMap), but for a sequence of operations, you're stuck with either a lock or a synchronized block.
For some operations you can employ what is called a "safe sequence", where concurrent operations may overlap without conflicting. For instance, you might be able to add a member to a set (in theory) without the need to synchronize, since two threads simultaneously adding the same member do not conceptually conflict with each other.
But to query one object and then conditionally operate on a different object is a much more complicated scenario. If your sequence was to query the set, then conditionally insert the member into the set and into the queue, the query and first insert could be replaced with a "compare and swap" operation that syncs without stalling (except perhaps at the memory access level), and then one could insert the member into the queue based on the success of the first operation, only needing to synchronize the queue insert itself. However, this sequence leaves the scenario where another thread could fail the insert and still not find the member in the queue.
Since the contention case is the relevant case you should look at "spin locks". They do not give away the CPU but spin on a flag expecting the flag to be free very soon.
Note however that real spin locks are seldom useful in Java because the normal Lock is quite good. See this blog where someone had first implemented a spinlock in Java only to find that after some corrections (i.e. after making the test correct) spin locks are on par with the standard stuff.
You can use java.util.concurrent.ConcurrentHashMap to get the semantics you want. They have a putIfAbsent that does an atomic insert. You then essentially try to add an element to the map, and if it succeeds, you know that thread that performed the insert is the only one that has, and you can then put the item in the queue safely. The other significant point here is that the operations on a ConcurrentMap insure "happens-before" semantics.
ConcurrentMap<Element,Boolean> set = new ConcurrentHashMap<Element,Boolean>();
Queue<Element> queue = ...;
void maybeAddToQueue(Element e) {
if (set.putIfAbsent(e, true) == null) {
queue.offer(e);
}
}
Note, the actual value type (Boolean) of the map is unimportant here.
Hey guys,
I am reading these so called non-blocking techniques, but i have few doubts :
1) lock-free operation are performed using atomic operation, now what are these atomic operation ? i mean at certain level they also need to have a lock right ? so Does this lock-free approach provides us locking at finer granularity only ?
2) they say non-blocking list, Now what a non-blocking list should be : if more than one threads comes at the same insertion, only one is going to get succeed, another one will do some other work right ?, but if other thread has no choice except inserting a node then how come it is non-blocking ? won't it will get blocked until previous one is done ??
3) In java, how do they atomic operation ? doesn't they do something like synchronized boolean .....
so how it is lock-free since they are acquiring lock i.e. synchronized section ?
4) CAS is usually used to implement atomic operation. So doesn't cas allow only one operation to happen on the same object , and stops ( block ) others those want to operate on the same object ?
Sorry for so many doubts...
please clarify...
EDIT
what happens when i have a structure to update ? does it also supported by hardware ? No right, So doesn't language would be acquiring locks at some level to make these structure operation atomic ?
About JAVA : there are AtomicReference and AtomicReferenceFieldUpdater class which provides updation to a object ( structure or any kind of object) , so can we compare them in terms of performance i mean speed ? Both in tern uses Unsafe class which uses Native class .
Here is a simple lock free method in AtomicInteger
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
You can see that it gets the value, increments it and does a compareAndSwap. If the compareAndSwap doesn't find the expect value, it means another thread has changed the value. So it tries again, and again, until all other threads trying to change the value have done so. This is lock free as no lock is used, but not blocking free as it may have to try again (which is rare) more than once (very rare)
1) lock-free operation are performed using atomic operation, now what are these atomic operation ? i mean at certain level they also need to have a lock right ? so Does this lock-free approach provides us locking at finer granularity only ?
However locks are implemented using more primitive operations. Otherwise you would need a lock to implement a lock adnauseum. The lock free approach uses atomic operations which avoid a full blown lock.
2) they say non-blocking list, Now what a non-blocking list should be : if more than one threads comes at the same insertion, only one is going to get succeed, another one will do some other work right ?,
If its thread safe they should both succeed, one at a time.
but if other thread has no choice except inserting a node then how come it is non-blocking ?
The term is "concurrent". It still has to wait for the other thread to finish, it uses a lock-free approach to do this.
won't it will get blocked until previous one is done ??
yes.
3) In java, how do they atomic operation ?
There is a call native method which performs the atomic operations. You can see this by reading the code. ;) From look at the native code generated, these native method are turned into machine code instructions for performance (rather than being a true method call)
doesn't they do something like synchronized boolean ..... so how it is lock-free since they are acquiring lock i.e. synchronized section ?
No, if you read the code, you would see that it doesn't.
4) CAS is usually used to implement atomic operation. So doesn't cas allow only one operation to happen on the same object ,
No.
and stops ( block ) others those want to operate on the same object ?
No.
Again, if you look at how it is used it may make more sense.
1) lock-free operation are performed using atomic operation, now what are these atomic operation ?
E.g. incrementing a counter includes
reading the current value,
incrementing the value in memory,
writing back the updated value.
Atomicity means that these all happen as one single, uniterruptible change.
i mean at certain level they also need to have a lock right ?
Wrong. The basic idea behind CAS is to do the first two steps above, then before the third, they check whether the value was changed in between, and fail if so. Then the change may be retried with the new value later.
There is no classical locking involved, as each of the 3 steps in itself is atomic. The 3rd (Compare And Swap) operation is supported by modern processors, so you may say it involves some sort of locking at the register level (to be frank, I don't know how exactly it is implemented), but at any rate, that is not the same as what is generally meant by locking in Java.
The benefit of CAS is improved performance due to the fact that even with the improved locking performance in current JVMs, CAS is still cheaper, especially in case of contention (i.e. when multiple threads do collide upon an operation). In this case, using locks, one or more of the threads are suspended, and a new thread is brought into context instead, which is a very costly operation even when it doesn't involve swapping memory.
2) they say non-blocking list, Now what a non-blocking list should be
Here you may be confusing two different terms. A non-blocking list is one which does not block on insertions/removals, which usually means its size is not bounded (e.g. CopyOnWriteArrayList). Contrast this with e.g. a blocking queue (e.g. ArrayBlockingQueue), which has a fixed maximum size, and upon reaching its size limit, additional insert calls are blocked until more space is available (after some other thread removes element(s) from the queue).
A collection which achieves thread safety using a lock-free algorithm (such as ConcurrentHashMap) is not the same as a non-blocking collection.