I am attempting to use synchronize method in spring controller. Because our Payment gateway hits method [@RequestMapping(value="/pay",method=RequestMethod.POST)] different transactions [txn id : txn01 & txn02] at a time. But these 2 different transaction processing one by one than parallel due to using synchronize block.
Problem -> Why i am using synchronize block in controller is that say Transaction [txn01] hits [@RequestMapping(value="/pay",method=RequestMethod.POST)] twice like duplicate call from payment gateway. before finishing first call [backend processing] i get second call from payment gateway for same tran id.
Is there any way to process two different transaction parallel with using transaction id in synchronize block other than duplicate call i mean same tran id. Please advice me.
Please let me know if my question is unclear.
@RequestMapping(value="/pay",method=RequestMethod.POST)
public String payAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
synchronized (this) {
return this.processPayAck(httpRequest, httpResponse, session);
}
}
public synchronized String processPayAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
// Payment Acknowledgment process here
if (sametranIDNotExists) {
// first call here
callWS(); - processing business logic.
return someURL;
} else {
// Gets second call here before first call completed
return someURL;
}
}
Modified code :
Is it correct way to use intern inside synchronize block.
@RequestMapping(value="/pay",method=RequestMethod.POST)
public String payAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
String tranID = httpRequest.getParameter("tranID");
synchronized (String.valueOf(tranID).intern()) {
return processPayAck(httpRequest, httpResponse, session);
}
}
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.
A synchronized method provides a lock corresponding to object-level or Class level ( i.e class level means static method ), whereas, synchronized block provides a lock on any object depending on the parameter.
A Synchronized block is a piece of code that can be used to perform synchronization on any specific resource of the method. A Synchronized block is used to lock an object for any shared resource and the scope of a synchronized block is smaller than the synchronized method.
I'm not sure if you are working in a distributed environment.
If there is only one machine, you can remove the syncronized keyword and create name-based locks with your transation id instead.
If this program is working in a cluster and there are multiple machines, which means the request might be assigned to different machine, I think you need to aquaire distribution-lock with Redis or other frameworks.
Synchronized block is used to provide thread safety. Also when multiple threads are trying to access same object, thread only with object level lock can acces synchronized(this)
block. While one among a group of threads get object level lock, rest of the threads wait (Threads access synchronised block one by one but not in parallel).
Appropriate use : Use synchronized block when threads are trying modifying same resource(to avoid data inconsistancy). In this case threads are trying to modify same database resource. But as mentioned modifications are done on 2 different transactions(rows).
If modifying one row doesn't harm the other one then it is not required to use the line
return this.processPayAck(httpRequest, httpResponse, session);
within synchronised block. Instead it could be written as:
@RequestMapping(value="/pay",method=RequestMethod.POST)
public String payAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
return this.processPayAck(httpRequest, httpResponse, session);
}
Suggestion : Use CopyOnWriteArrayList
(as an instance variable not local variable) to store transaction id at the end of payAck
method and use contains("textId")
method to check whether the given transaction id is using payAck
method again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With