Java - 静态 block 和线程同步问题 - 一个案例

标签 java multithreading smpp

要做什么?

  1. 从此处下载logica smpp jar (215 KB):http://opensmpp.logica.com/CommonPart/Download/library_1_3/smpp_full.tar.gz
  2. 编写一个小测试代码:

    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();
        }
    }
    
  3. 运行此main方法。

会发生什么?

线程被阻塞(大概是在互相等待)

我的分析:

  • DataSMOutbind 类都有一个共同的祖先 PDU,它有一个 static block 使用以下代码:

    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,以便它可以创建其子对象,例如BindTransmitterDataSMOutbind等通过 createPDU

提供的工厂方法
  • 因此,当我的测试应用程序执行时,一个Thread 会进入 PDU 的静态方法(同时初始化 DataSM)。两个线程已开始初始化Outbind,等待其中一个完成初始化PDU

  • 但是在运行 PDU 静态方法的 ONE 中的某个时刻,它尝试初始化 Outbind,并且看到 TWO 已经启动了相同的操作,它等待 TWO 完成。

  • 所以一和二正在等待对方完成

  • 我如何才能确信此问题与静态 block 加载有关?
    只需添加以下一行作为测试代码的 main 方法中的第一条语句,即可使其正常工作,并且 Thread 不再阻塞:

    Class.forName("com.logica.smpp.pdu.PDU");
    

我的问题是:

  1. 我的分析正确吗?
  2. 这是与静态 block 相关的已知线程同步问题吗?
  3. 需要练习什么经验法则才能避免遇到这种情况?

更新

  • 在此处添加 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;
    }
    
  • DataSMOutbind 以及 PDU 的其他子类的构造函数做什么?
    除了初始化一些实例变量之外什么都没有。这些是 POJO。他们不保留任何外部资源,如文件、数据库等。

最佳答案

您的线程可能会阻塞,但原因并非您想象的那样。静态初始值设定项在类加载时执行,而不是在创建实例时执行。因此,您不会让两个对象“进入”静态初始化程序,并在某个时刻在某些共享变量上陷入僵局。

如果不知道您正在使用的库的确切细节,就很难诊断真正的问题是什么,但我建议转储您的线程并使用合适的工具对其进行分析。

关于Java - 静态 block 和线程同步问题 - 一个案例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15048971/

相关文章:

java - Android Java 在单独的线程中运行类似于 C# 风格的 Action 列表

ios - App Like Ovoo 视频通话

ssl - 电信中广泛使用的 SMPP 的安全性

java - 删除目录时显示问题

java - Spring 的新手 - 应用程序上下文何时/何地实例化所有 bean

java - HTTP GET 请求后,结果字符串被截断——内容已被消费

检查 pthread_cond_t 的值

java - 运行时权限问题

c 多线程进程

java - 我正在尝试连接到smpp服务器!我收到连接超时异常