What is to be done?
- Download logica smpp jar (215 KB) from here: http://opensmpp.logica.com/CommonPart/Download/library_1_3/smpp_full.tar.gz
Write a small test code:
package com.logica.smpp; import com.logica.smpp.pdu.DataSM; import com.logica.smpp.pdu.Outbind; public class PDUTest { public static void main(String... args) throws InterruptedException { Thread thread1 = new Thread(new Runnable() { @Override public void run() { System.out.println(new DataSM().debugString()); } }); thread1.setName("ONE"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { System.out.println(new Outbind().debugString()); } }); thread2.setName("TWO"); thread1.start(); thread2.start(); } }
Run this
main
method.
What happens?
The Thread
s are blocked (Presumably waiting for each-other)
My analysis:
Both
DataSM
andOutbind
classes have a common ancestorPDU
, which has astatic
block with the following code:static { pduList = new Vector(30,4); pduList.add(new BindTransmitter()); pduList.add(new BindTransmitterResp()); pduList.add(new BindReceiver()); pduList.add(new BindReceiverResp()); pduList.add(new BindTransciever()); pduList.add(new BindTranscieverResp()); pduList.add(new Unbind()); pduList.add(new UnbindResp()); pduList.add(new Outbind()); pduList.add(new SubmitSM()); pduList.add(new SubmitSMResp()); pduList.add(new SubmitMultiSM()); pduList.add(new SubmitMultiSMResp()); pduList.add(new DeliverSM()); pduList.add(new DeliverSMResp()); pduList.add(new DataSM()); pduList.add(new DataSMResp()); pduList.add(new QuerySM()); pduList.add(new QuerySMResp()); pduList.add(new CancelSM()); pduList.add(new CancelSMResp()); pduList.add(new ReplaceSM()); pduList.add(new ReplaceSMResp()); pduList.add(new EnquireLink()); pduList.add(new EnquireLinkResp()); pduList.add(new AlertNotification()); pduList.add(new GenericNack()); }
It creates pduList
so that it can create objects of its children like BindTransmitter
, DataSM
, Outbind
etc via a factory method which it provides at createPDU
So when my test application gets executed, ONE
Thread
enters PDU's static method (while initialisingDataSM
). And the TWOThread
, which has started initialisingOutbind
waits for ONE to finish initialisingPDU
.But at some point in ONE which is running static method of
PDU
, it tries to initialiseOutbind
, and seeing that TWO has already started the same thing, it waits for TWO to finish.So ONE and TWO are waiting for each-other to finish
How can i be confident that this issue is related to static block loading?
Adding just this following one line as the first statement in the main method of test code, makes it work and theThread
s do not block anymore:Class.forName("com.logica.smpp.pdu.PDU");
My Questions are these:
- Is my analysis correct?
- Is this a known
Thread
synchronisation issue concerning with static blocks? - Any thumb rule that needs to be practiced to not stumble onto this situation?
Update
Adding the factory method for PDU here:
public static final PDU createPDU(int commandId) { int size = pduList.size(); PDU pdu = null; PDU newInstance = null; for (int i = 0; i < size; i++) { pdu = (PDU)pduList.get(i); if (pdu != null) { if (pdu.getCommandId() == commandId) { try { newInstance = (PDU)(pdu.getClass().newInstance()); } catch (IllegalAccessException e) { } catch (InstantiationException e) { } return newInstance; } } } return null; }
What do the constructors of
DataSM
,Outbind
and other child classes ofPDU
do?
Nothing, except initialising a few instance variables. These are POJOs. They do NOT hold on to any external resources like file, database etc.