gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 04:29:17 25 4
gpt4 key购买 nike

要做什么?

  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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com