Selva
Selva

Reputation: 1670

rest api data mismatch in concurrent request

In my project we are using restful webservices with spring framework, when I call the same request concurrently the property of the object is overriden by one another.

Below is my code.

@Service("testService")
@Scope(value ="prototype")
public class TestServiceImpl extends DefaultServiceBuilder {

        public void test() {
                 process();
                 System.err.println(tranLog.getTxnId());

        }
}


  public class DefaultServiceBuilder {

protected TransactionLog tranLog;

public void process() {
    tranLog = new TransactionLog();
    Random r = new Random();
    String rid = r.nextInt(40000)+"";
    tranLog.setTxnid(rid);
    setTranLog(tranLog);
}


    public TransactionLog getTranLog() {
        return tranLog;
    }

    public void setTranLog(TransactionLog tranLog) {
        this.tranLog = tranLog;
    }
}

public class TransactionLog {
   private String txnId;

   public void setTxnId(String txnId) {
        this.txnId = txnId;
   }

   public String getTxnId() {
        return txnId;
   }
}

I am calling the below request with 2 thread parallel.

My expected input is 
123456
242422

But the output is 
242422
242422

Why the TransactionLog object value is overriding eventhough i gave scope prototype. How to access the Transalog object safely?

Any help will be greatly Appreciated!!!!

Upvotes: 1

Views: 502

Answers (2)

Anton Tupy
Anton Tupy

Reputation: 969

Class name TransactionLog implies that evety instance of TransactionLog, writed to variable tranLog will be used only in one thread.

If it right, then read further:

In very good book "Java Concurrency in Practice" described one good pattern of thread synchronization:

Thread Confinement

Accessing shared, mutable data requires using synchronization; one way to avoid this requirement is to not share. If data is only accessed from a single thread, no synchronization is needed. This technique, thread confinement, is one of the simplest ways to achieve thread safety. When an object is confined to a thread, such usage is automatically thread-safe even if the confined object itself is not [CPJ 2.3.2].

Make field tranLog just local variable

final TransactionLog tranLog = new TransactionLog();

If you use it in other function, for instance subProcess2:

private void subProcess2() {
    tranLog.doSometthing();
}

Add tranLog to function parameters:

private void subProcess2(TransactionLog tranLog) {
    tranLog.doSometthing();
}

And pass tranLog when calling subProcess2.

Upvotes: 1

Ravi
Ravi

Reputation: 31417

You could synchronize your code, by synchronizing below line of code

protected static TransactionLog tranLog;

public static synchronized void process() {
    Random r = new Random();
    tranLog = new TransactionLog();
    String rid = r.nextInt(40000)+"";
    tranLog.setTxnid(rid);
}

Making static synchronized will allow only one thread at any given time.

Upvotes: 1

Related Questions