cancel
Showing results for 
Search instead for 
Did you mean: 

synchronized method in a java class used by many interfaces

Former Member
0 Kudos

My interface (idoc to file) is using a java class, which has one method that reads a table from a central database and after doing some calculations updates it.

(The interface instantiate the class inside a user-defined function and calls the method there.)

The problem is that if somebody sends 100 idocs at the same time, there can be a “dirty read”, I mean, a read just before other interface updates the table.

We want the following:

Interface 1:

- Read counter from the table (counter = 5 )

- Increment counter (counter = 6)

- Update table with that counter (table with counter = 6)

Interface 2:

- Read counter from the table (counter = 6 )

- Increment counter (counter = 7)

- Update table with that counter (table with counter = 7)

RESULT: The table has the counter = 7

But what is happening is the following:

- Interface 1 reads (counter = 5)

- Interface 2 reads (counter = 5)

- Interface 1 increments counter (counter = 6)

- Interface 2 increments counter (counter = 6)

- Interface 1 updates table (table with counter = 6)

- Interface 2 updates table (table with counter = 6)

RESULT: The table has the counter = 6 (WRONG)

I made the method synchronized. What I was expecting was that only one interface (i1) could enter the method (read the table and update it) while other interfaces running at the same time would have to wait until i1 finished that method.

My first test indicates that's not happening. Can anybody help me to find a solution?

Accepted Solutions (0)

Answers (2)

Answers (2)

Former Member
0 Kudos

Hi,

In this case processing of IDOCs with quality of service exactly once in order can help. But you can achieve it if client is able to send IDOCs in an order. You can configure it in partner profile inside your sender system.

Regards,

Wojciech

Former Member
0 Kudos

Hi Jorge,

the problem is that for every instance of mapping program you create a new object with a new synchronized method.

So your synchronized method is only synch. inside the running mapping program that means that the 2nd idoc will use a different mapping program so a different instance of your object with the synch method will be created/used.

You could try using a singleton class, that means there can be only one instance of your class with the method synchronized inside the Java Virtual Machine.

Regards,

Sergio

Former Member
0 Kudos

Sergio, you say

--> "the problem is that for every instance of mapping program you create a new object with a new synchronized method. "

But that shouldn't be a problem. That's what synchronized methods are for. There can be many objects of the same type (class) running at the same time but the JVM controls that only one enters in the synchronized method.

The class is loaded into XI in Imported Archives, and every idoc that is sent instantiates the class and calls that method.

Former Member
0 Kudos

Hi

to serialize Idocs see the below links

How to serialize IDoc XML messages fed into XI - /people/community.user/blog/2006/11/04/how-to-serialize-idoc-xml-messages-fed-into-xi

serialization /people/alessandro.guarneri/blog/2006/11/26/content-based-serialization-dynamic-queue-name-in-xi

Regards

Chilla

Former Member
0 Kudos

Hi Jorge,

synchronized methods guarantee the queued access to a method of an object.

That means that if you have two instances of the same class <b>O</b>, let's call them <b>O1</b> and <b>O2</b>, with a method named <b>read</b> (synchonized) if object X1 and X2 try to call <i>O1.read</i> they will be queued but if X1 calls <i>O1.read</i> and at the same time X2 calls <i>O2.read</i> there is no queueing because the call is performed on different objects.

The same happens with mapping programs, the first idoc is handled by mapping program1 that use <i>O1.read</i> and the second idoc is handled by mapping program 2 that call <i>O2.read</i>, that's why u see no queuing happening.

Regards,

Sergio

bhavesh_kantilal
Active Contributor
0 Kudos

Am not a java punter but I loved this discussion.

Just got a few queries which I hope you can answer,

Assuming that the sender System sends the IDOc's with a QOS of EOIO and I still want to implement this concept on Synchronoized Methods, how should i do this?

Can you provide a sample code excerpt?

Thanks for this amazing info,

regards

Bhavesh

Former Member
0 Kudos

Hi Bhavesh,

If the QOS is EOIO this means that the integration engine manage the call to the mapping program (and all the other blocks) inside an "internal" synchronized method.

So this means that in this case you do not need to manage the queued access (synchronization) inside your custom java code because it is already enveloped in a queued block by XI.

The problem that Jorge had can be easily reproduced using the sample code that follows:

-


<b>class Synch Object</b>



import java.util.Date;

public class SynchObject {
	String strName;
	public SynchObject(String strName){
		this.strName = strName;
		
	}
	
	
	public synchronized void syncWrite(String strCaller) throws InterruptedException{
		Date now;
		
		now = new Date();
		System.out.println("-- " + now.toLocaleString() + " " + strCaller + " entering syncWrite of " + strName);
		System.out.flush();
		
		Thread.sleep(1000);
		now = new Date();
		System.out.println("-- " + now.toLocaleString() + " syncWrite of " + strName + " called by " + strCaller );
		System.out.flush();
		
		Thread.sleep(1000);
		now = new Date();
		System.out.println("-- " + now.toLocaleString() + " " + strCaller + " leaving syncWrite of " + strName);
		System.out.println("");
		System.out.flush();
	}

}

-


<b>class Caller</b>


public class Caller implements Runnable {

	String strName;
	SynchObject target;
	int intMax;
	
	public Caller(String strName, SynchObject target, int intMax) {
		this.strName = strName;
		this.target = target;
		this.intMax = intMax;
	}

	public void run() {
		for(int i=0; i<intMax;i++)
			try {
				target.syncWrite(strName);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}
}

-


<b>class Workbench</b>


public class Workbench {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SynchObject sObj1 = new SynchObject("syncObj1");
		SynchObject sObj2 = new SynchObject("syncObj2");
		
		Caller c1 = new Caller("caller1",sObj1,2);
		Caller c2 = new Caller("caller2",sObj1,2); '[*CHANGE*]
	
		Thread ct1 = new Thread(c1);
		Thread ct2 = new Thread(c2);
		ct1.start();
		ct2.start();
	}

}

Run the workbench class to see what happen when setting QOS EOIO (the synch object is the same).

To see instead what happen now (missing synchronization) you have to change in Workbench class the statement

Caller c2 = new Caller("caller2",sObj1,2); '[*CHANGE*]

with

Caller c2 = new Caller("caller2",sObj2,2); '[*CHANGE*]

The reason is that every instance of the mapping program declare a new instance of the "Synchronized object" so the calls are synchronized inside the same mapping program but not between several mapping program.

Hope this give you a better idea on this problems with java synchronization, but if you have further doubts (I know it's a little bit tricky ) feel free to ask.

Kind Regards,

Sergio