1

何を終わらせるべきなのですか?

  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メソッドを実行します。

何が起こるのですか?

Threadブロックされています (おそらくお互いを待っています)

私の分析:

  • DataSMとクラスの両方にOutbind共通の祖先があり、次のコードをPDU含むブロックがあります。static

    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の子のオブジェクトを作成できるように作成しますBindTransmitterDataSMOutbindcreatePDU

  • したがって、テスト アプリケーションが実行されると、ONEThreadは PDU の静的メソッドに入ります (初期化中DataSM)。そして、Thread初期化を開始した TWO は、 OutbindONE の初期化が完了するのを待ちますPDU

  • しかし、 の静的メソッドを実行している ONE のある時点で、PDUを初期化しようとしOutbind、TWO がすでに同じことを開始していることを確認して、TWO が終了するのを待ちます。

  • だからONEとTWOはお互いが終わるのを待っている

  • この問題が静的ブロックの読み込みに関連していると確信するにはどうすればよいですか?
    テスト コードの main メソッドの最初のステートメントとして次の 1 行を追加すると、動作し、Threads はブロックされなくなります。

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

私の質問は次のとおりです。

  1. 私の分析は正しいですか?
  2. Threadこれは、静的ブロックに関する既知の同期の問題ですか?
  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 です。ファイル、データベースなどの外部リソースを保持しません。

4

4 に答える 4

1

あるクラスの初期化子が別のクラスに依存している場合、またはその逆の場合、2つのクラスが2つの異なるスレッドで初期化されると、デッドロックが発生する可能性があります。あなたの分析はおそらく正しいでしょう。

これらの2つのクラスが同じスレッドで初期化される場合、デッドロックは発生しません。それでも、循環依存は避ける必要があります。この例では、pduListものは独自のクラスにある必要があります。

于 2013-02-24T20:23:59.587 に答える
1

あなたのスレッドはブロックしているかもしれませんが、あなたが考える理由ではありません。静的初期化子は、インスタンスの作成時ではなく、クラスのロード時に実行されます。したがって、2つのオブジェクトが静的初期化子に「入り」、ある時点で共有変数でデッドロックすることはありません。

使用しているライブラリの正確な詳細がわからないと、実際の問題が何であるかを診断するのは困難ですが、スレッドをダンプして、適切なツールで分析することをお勧めします。

于 2013-02-24T05:35:18.140 に答える
0

lock(pduList)の FIRST ステートメントとして追加してくださいcreatePDUlockの直後にブロックを閉じますreturn。試してみてください。どうすればいいのか教えてください。

例えば

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  
}
于 2013-02-25T00:22:14.180 に答える
0

ツールを使用して、jstackスレッド スタックを出力できます。

jstack <pid of your java process>

コマンドを介してpidを見つけることができますjps。たとえば、jps私のマシンのコマンド出力:

eric@erics-MacBook-Pro:~$ jps
577 Jps
448 

次に、448jstackを使用したコマンド:pid

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」がブロックされていることがわかりますObject.wait()

スレッドスタックを取得したときにコードがブロックされる理由は明らかです。

于 2013-02-24T05:40:53.553 に答える