Synchronized Method In Spring MVC

10,566

Solution 1

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.

Solution 2

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.

Share:
10,566
deadend
Author by

deadend

Java developer

Updated on July 26, 2022

Comments

  • deadend
    deadend almost 2 years

    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);
        }
    }
    
  • deadend
    deadend over 6 years
    Can we synchronize by some variable like transaction id
  • xingbin
    xingbin about 6 years
    @DEADEND You can try this synchronized (String.valueOf(transactionId).intern())
  • xingbin
    xingbin about 6 years
  • deadend
    deadend about 6 years
    @user27149.. from synchronized (String.valueOf(transactionId).intern()) transaction id should be instance variableor method local variable. somebody not preferring not to use intern in synchronize block