Java-静态块和线程同步问题-一个案例 该怎么办? 从以下位置下载logica smpp jar(215 KB):
编写一个小测试代码:Java-静态块和线程同步问题-一个案例 该怎么办? 从以下位置下载logica smpp jar(215 KB):,java,multithreading,smpp,Java,Multithreading,Smpp,编写一个小测试代码: 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 Runn
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();
}
}
main
方法线程
被阻塞(可能正在等待对方)
我的分析是:
和DataSM
类都有一个共同的祖先Outbind
,它有一个带有以下代码的PDU
块:静态
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()); }
pduList
,以便通过它在createPDU
提供的工厂方法创建其子对象,如BindTransmitter
、DataSM
、Outbind
等
- 因此,当我的测试应用程序执行时,一个
线程进入PDU的静态方法(初始化
)。两个DataSM
,它已开始初始化线程
,等待一个线程完成初始化Outbind
PDU
- 但是,在一个运行静态方法
的程序中,它试图初始化PDU
,看到两个已经开始了相同的事情,它就等待两个完成Outbind
- 所以一个和两个都在等待对方完成
- 我如何才能确信此问题与静态块加载有关?
在测试代码的主要方法中添加以下一行作为第一条语句,可以使其正常工作,线程不再阻塞:
Class.forName("com.logica.smpp.pdu.PDU");
线程同步问题吗
- 在此处添加PDU的出厂方法:
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; }
公共静态最终PDU createPDU(int commandId) { int size=pduList.size(); PDU PDU=null; PDU newInstance=null; 对于(int i=0;i
、DataSM
和Outbind
的其他子类的构造函数做什么?PDU
什么都没有,只是初始化了几个实例变量。这些是波乔。他们不保留任何外部资源,如文件、数据库等
- 您的线程可能会阻塞,但不是因为您认为的原因。静态初始值设定项在加载类时执行,而不是在创建实例时执行。因此,您不会让您的两个对象“进入”静态初始值设定项,在某个点上,在某个共享变量上陷入死锁
如果不知道您正在使用的库的确切细节,就很难诊断出真正的问题是什么,但我建议您转储线程并使用合适的工具对其进行分析
jstack
工具打印线程堆栈:
jstack <pid of your java process>
然后使用pid
448执行jstack
命令:
jstack 448
以及部分输出:
"Worker-46" prio=5 tid=10f543800 nid=0x11811e000 in Object.wait() [11811d000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <7a0001a80> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
- locked <7a0001a80> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
“Worker-46”prio=5 tid=10f543800 nid=0x11811e000在Object.wait()中[11811d000]
java.lang.Thread.State:定时等待(在对象监视器上)
在java.lang.Object.wait(本机方法)
-等待(org.eclipse.core.internal.jobs.WorkerPool)
位于org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
-锁定(org.eclipse.core.internal.jobs.WorkerPool)
位于org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
位于org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
您可以在对象中看到“Worker-46”被阻塞。wait()
获取线程堆栈时,应该清楚代码阻塞的原因。如果一个类的初始值设定项依赖于另一个类,反之亦然,则如果两个类在两个不同的线程中初始化,则可能导致死锁。你的分析很可能是正确的 如果这两个类在同一个线程中初始化,就不会出现死锁;然而,应该避免循环依赖。在本例中,
pduList
内容应该在它自己的类中。请将lock(pduList)
添加为createPDU
中的第一条语句。在返回后立即关闭锁
块。请试一试。让我知道你是怎么做的
e、 g
公共静态最终PDU createPDU(int commandId)
{
锁(pduList){
int size=pduList.size();
PDU PDU=null;
PDU newInstance=null;
对于(int i=0;i
但是正如您从我的测试应用程序中注意到的,当线程开始执行时,DataSM
和Outbind
这两个类都是第一次加载的。因此,它们的祖先PDU
的静态块被输入到这些线程的范围中。此外,此库的源代码也可用。这些对象是POJO。它们根本不保留任何外部资源。除非您的类被加载到不同的类加载器中,否则情况就不会如此。斯达
"Worker-46" prio=5 tid=10f543800 nid=0x11811e000 in Object.wait() [11811d000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <7a0001a80> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
- locked <7a0001a80> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
public static final PDU createPDU(int commandId)
{
lock(pduList) {
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;
} // end lock
}