I am implementing transferring money from bank account to another bank account. My question is if I have #Transactional annotation (from guice) do I have to use synchronize ? Does Transactional ensure that another thread wont hit the resource ?
#Transactional(rollbackOn = RuntimeException.class)
synchronized public void transfer(#NonNull final Transfer transfer) {
withdrawFromOwnerAccount(ownerAccount, transfer.getAmount());
depositToReceiverAccount(receiverAccount, transfer.getAmount());
}
"UnitOfWork is threadsafe and can be cached for multiple uses or injected directly into singletons." see
Therefore, my answer is yes.
Btw. Synchronized will only be effective if the threads handle the same object, (Singleton?).
Important is that the underlying dbms can handle transactions in a safe way. I assume a kind of mysql or postgres are used. The framework should make sure that the connection used to do the transaction and database operations is used exclusively in one thread during one transaction. That's a quite simple requirement and handled quite safely in java-servers for 20 years.
Related
Let's say that we have this code:
#Transactional
public String getUser(long id) {
User user = userDao.getUserById(id);
if(user == null) {
user = new User();
user.setXXX(XXX);
userDao.insert(user);
}
}
Assuming that datasource is mysql5:
How many transactions do we get if two threads visit getUser() method at the same time? If the answer is two, then what is the relationship between the two transactions?
As of Spring Documentation:
The getTransaction(..) method returns a TransactionStatus object,
depending on a TransactionDefinition parameter. The returned
TransactionStatus might represent a new transaction, or can represent
an existing transaction if a matching transaction exists in the
current call stack. The implication in this latter case is that, as
with Java EE transaction contexts, a TransactionStatus is associated
with a thread of execution.
Which means that for every thread Spring will create a new transaction, unless there is already one existing for that thread.
When two threads enter this method, two separate transactions are created and there is no relation between them. There is no nesting or anything going here (that is a different scenario). The only case that i can think of where there would be any relation is when the Propagation.REQUIRES_NEW is used, but this is not the case here.
How many transactions do we get if two threads visit getUser() method at the same time?
The answer to this depends on the connection factory and the database type. If you are using a connection pool or otherwise creating two connections then each thread will get a separate transaction with the database. The details here are highly dependent on your connection pool and database settings.
If the answer is two, so what is the relationship between the two transactions?
This depends on what the database does with these transactions. It is important to realize that transactions are not about mutex but are rather about database coherency. To quote from wikipedia:
A transaction symbolizes a unit of work performed within a database management system (or similar system) against a database, and treated in a coherent and reliable way independent of other transactions. A transaction generally represents any change in database.
How the transactions interact depends highly on what type of transaction is created and what is being done inside them. If you are asking if it is possible for 2 threads to lookup a User with the same id at the same time and then try and create the same User twice then the answer is definitively yes.
One problem with this is that both userDao.insert(...) calls might succeed but the 2nd one to commit its transaction (race condition alert) might throw some sort of unique constraint exception but that might at a AOP level and not in your code.
In my spring web app, I have a service method containing a block of code guarded by a lock.
Only a single thread can enter the code block at a time.
This works fine in a non clustered environment but fails in a clustered one. In a clustered environment, within a node, synchronization happens but among different nodes, code block is executed in parallel. Is this because in each node a separate Lock object is created ?
Can anyone advise me ?
Code Sample
//Service Class
#Service
class MyServiceClass {
private final Lock globalLock;
#Autowired
public MyServiceClass(#Qualifier("globalLock") final Lock globalLock){
this.globalLock = globalLock;
}
public void myServiceMethod(){
...
globalLock.lock();
try {
...
}
finally {
globalLock.unlock();
}
...
}
}//End of MyServiceClass
//Spring Configuration XML
<bean id="globalLock" class="java.util.concurrent.locks.ReentrantLock" scope="singleton" />
If you want to synchronize objects in a cluster environment, this meaning many VMs involved, your solution would involve some kind of communication between the different VMs involved.
In this case, it will require some imagination to get the thing done: you will need the mutual exclusion implemented on some object that is common to all the VMs involved, and that may escalate when you put additional machines into the cluster. Have you thought some solution based on JNDI? Here you have something on it, but I am afraid it looks rather an academic discussion:
http://jsr166-concurrency.10961.n7.nabble.com/Lock-implementation-td2180.html
There is always the chance to implement something based on DB mechanisms (always thinking that your DB is a central and common resource to all the nodes in the cluster). You could devise something based on some SELECT FOR UPDATE mechanism implemented in your database, over some table used only for synchronization...
You have an interesting problem! :) Good luck
You are right, the reason is that each node has it's own lock. To solve this, consider introducing in the database a table SERVICE_LOCKS, with the columns service class name, service Id, lock status and acquisition timestamp.
For service Id make each service generate a unique distributed Id using UUID.randomUUID().
To acquire the locks, issue an update to try to grab it, and then query it to see if you have the lock. But don't do select, check and then update. Locks older than a certain amount of time should be not taken into account.
This is an implementation of to the coarse grained lock design pattern, where an application level pessimistic lock is acquired to lock shared resources.
Depending on the business logic on the services and the type of transaction manager you use, increasing the isolation level of the service method to REPEATABLE_READ might be an option.
For a solution that does not involve the database, have a look at a framework for distributed concurrent processing based on the Actor concurrency model - The Akka Framework (click Remoting button).
I have a method in which some database insert operations are happening using hibernate and i want them to be thread safe. The method is getting some data in parametres and its a possiblity that sometimes two calls are made with same data at same point of time.
I can't lock those tables because of performance degradation. Can anyone suggest making the method as synchronized will solve issue?
Synchronizing a method will ensure that it can only be accessed by one thread at a time. If this method is your only means of writing to the database, then yes, this will stop two threads from writing at the same time. However, you still have to deal with the fact that you have multiple insert operations with the same data.
You should let Hibernate handle the concurrency, that's what it is meant to do. Don't assume Hibernate will lock anything: it supports optimistic transactions for exactly this purpose. Quote from the above link:
The only approach that is consistent with high concurrency and high scalability, is optimistic concurrency control with versioning. Version checking uses version numbers, or timestamps, to detect conflicting updates and to prevent lost updates. Hibernate provides three possible approaches to writing application code that uses optimistic concurrency.
Database Concurrency is handled by transactions. Transactions have the Atomic Consistent Isolated Durable (ACID) properties. They provide isolation between programs accessing a database concurrently. In the Hibernate DAO template of spring framework there are single line methods for CRUD operations on the database. When used individually these don't need to be synchronized by method. Spring provides declarative (XML), programmatic and annotation meta-data driven transaction management if you need to declare "your method" as transactional with specific propagation settings, rollbackFor settings, isolation settings. So in "your method" you can do multiple save,update,deletes etc and the ORM will ensure that it is executed with the transaction settings you have given in the meta-data.
Another issue is that the thread has to have the lock on all the objects that are taking part in the transaction.Otherwise the transaction might fail or the ORM will persist stale data. In another situation it can result in a deadlock because of lock-ordering. I think this is what really answers your question.
Both objects a and b have an instance variable of the type Lock. A boolean flag can be used to indicate the success of the transaction. The client code can retry the same transaction if it fails.
if (a.lock.tryLock()) {
try {
if (b.lock.tryLock()) {
try {
// persist or update object a and b
} finally {
b.lock.unlock();
}
}
} finally {
a.lock.unlock();
}
}
The problem with using synchronized methods is that it locks up the entire Service or DAO class making other service methods unavailable to other threads. By using individual locks on objects we can gain the advantage of fine grained concurrency.
No. This method probably uses another methods and objects, which may be not thread safe. synchronized makes threads to use that's method's object monitor only once at a time, so it makes thread-safe a method with respect to the object.
If you are sure that all other threads use shared functionality only with this method, then making it synchronized may be sufficient.
Choosing the best strategy depends on the architecture, sometimes to increase performance seems to be easier to use the trick like method synchronization, but this is bad approach.
There's no doubts, you should use transactions, and if with that strategy you're facing performance issues you should optimize your db queries or db structure.
Please remember that "Synchronization" should be as much as possible atomic.
i have a case where at my JAVA application, inside a transaction i want to call another service (JMS, WebService, SMS gate way, ...etc), i don't want to depend on the result of the call (Success, Fail, Exception thrown, ... etc), so if it fails somehow it won't affect my transaction completion,
what is the best approach to use this, am using Spring framework,
also i want to ask if i used threads for handling this, but my deployment will be on clusters(i.e different nodes with separate JVMs), what's the best way for handling (Lock, synchronization),
Regards,
You can could spawn a new thread (preferably via a java.util.Executor or a Spring TaskExecutor) to perform the subsidiary task. Spring's transaction synchronization works using non-inheritable ThreadLocal variables, so a new thread will not participate in the current transaction.
Alternatively, and perhaps more elegantly, you can specify an explicit transaction isolation level around the subsidiary task, something like:
#Transactional(propagation=Propagation.NOT_SUPPORTED)
public void doTheThing() { /.../ }
This will suspend the existing transaction for the duration of that method, although you'd still need to be careful with runtime exceptions not bubbling up into your main transaction boundary.
Regards your second question, locking and synchronisation in a cluster is a very complex topic, and not one I can really answer with the information you've given. I suggest opening a new question for this, and elaborate your requirements.
I'd schedule this in a quartz job.
Suppose we have a class called AccountService that manages the state of accounts.
AccountService is defined as
interface AccountService{
public void debit(account);
public void credit(account);
public void transfer(Account account, Account account1);
}
Given this definition, what is the best way to implement transfer() so that you can guarantee that transfer is an atomic operation.
I'm interested in answers that reference Java 1.4 code as well as answers that might use resources from java.util.concurrent in Java 5
Synchronize on both Account objects and do the transfer. Make sure you always synchronize in the same order. In order to do so, make the Accounts implement Comparable, sort the two accounts, and synchronize in that order.
If you don't order the accounts, you run the possibility of deadlock if one thread transfers from A to B and another transfers from B to A.
This exact example is discussed on page 207 of Java Concurrency in Practice, a critical book for anybody doing multi-threaded Java development. The example code is available from the publisher's website:
Dynamic lock-ordering deadlock. (bad)
Inducing a lock ordering to avoid deadlock.
A classic example very well explained here - http://www.javaworld.com/javaworld/jw-10-2001/jw-1012-deadlock.html?page=4
You probably need to have a full transactions support (if it's a real application of course).
The difficulty of solution hardly depends on your environment. Describe your system in detail and we'll try to help you (what kind of application? does it use web-server? which web-server? what is used to store data? and so on)
If you can guarantee that all accesses are made through the transfer method, then probably the easiest approach is just to make transfer a synchronized method. This will be thread-safe because this guarantees that only one thread will be running the transfer method at any one time.
If other methods may also access the AccountService, then you might decide to have them all use a single global lock. An easy way of doing this is to surround all code that accesses the AccountService in a synchronized (X) {...} block where X is some shared / singleton object instance (that could be the AccountService instance itself). This will be thread safe because only one thread will be accessing the AccountService at any one time, even if they are in different methods.
If that still isn't sufficient, then you'll need to use more sophisticated locking approaches. One common approach would be to lock the accounts individually before you modify them... but then you must be very careful to take the locks in a consistent order (e.g. by account ID) otherwise you will run into deadlocks.
Finally if AccountService is a remote service then you are into distributed locking territory.... unless you have a PhD in computer science and years of research budget to burn you should probably avoid going there.
Couldn't you avoid having to synchronize using an AtomicReference<Double> for the account balance, along with get() and set()?