7

私はSun jdk 1.5 ThreadPoolExecutor(24、24,60、TimeUnit.SECONDS、新しいLinkedBlockingQueue())を使用しています。soemtime jdbツールを使用して、スレッドプール内のすべてのスレッドのステータスが「モニターで待機中」であることを確認します。コードは次のとおりです。

    String key = getKey(dt.getPrefix(), id);
    synchronized (key.intern()) {      ----->

"synchronized (key.intern()) " に問題はありますか?


jdb ツールを使用して次の情報を取得します。24 スレッドのステータスは「モニターで待機中」です。これは、24 スレッドが「key.intern()」でデッドロックしていることを意味します。

(java.lang.Thread)0x28 pool-3-thread-2 モニターで待機中

(java.lang.Thread)0x27 pool-3-thread-3 モニターで待機中

(java.lang.Thread)0x1b pool-3-thread-4 モニターで待機中

(java.lang.Thread)0x1a pool-3-thread-5 モニターで待機中

(java.lang.Thread)0x19 pool-3-thread-6 モニターで待機中

(java.lang.Thread)0x18 pool-3-thread-7 モニターで待機中

(java.lang.Thread)0x17 pool-3-thread-8 モニターで待機中 ...

結果は次のとおりです。マルチスレッド環境では、Sting intern() メソッドがデッドロックになる可能性があります。

4

11 に答える 11

5

これに関連する質問を投稿したので、ぜひご覧ください: String オブジェクトの同期に問題がありますか?

私が学んだことは、インターンされた文字列を同期に使用することは悪い習慣です。

于 2008-12-08T14:54:59.710 に答える
4

とても。問題は、key.intern() がプールから文字列を返すため、実際にはそれほど一意ではないことです。String.intern() は、異なるオブジェクトで使用された場合でも、同じオブジェクトを返す場合があります。keyそれ自体を使用するか、別のオブジェクトを使用してみてください。

于 2008-12-08T09:28:49.977 に答える
2

2つの問題があります。1つは、文字列をロックとして使用しています。2つ目はデッドロックです。

文字列をロックとして使用すると、「who」と「where」がそのオブジェクトロックを取得する制御が失われます。

文字列のロックが原因である場合とそうでない場合があるデッドロックの問題。ただし、デッドロックの実際の理由は、「コードがデッドロックを引き起こす可能性がある」です。それが起こる可能性がある場合、それは起こります。

デッドロックを解決するには、スレッドのスタックをトレースする必要があります。

于 2008-12-08T13:18:58.343 に答える
2

コードはほぼ確実に、同じキーに影響を与えるアクションを同期しようとしています。したがって、intern()を呼び出して、同じキーが同じオブジェクトにマップされ、同期のオブジェクトとして有効であることを確認します。

問題は、そこでボトルネックが発生している場合(デッドロックではない)、同じキーを使用して同時に入ってくる操作が多すぎることです。

同期する必要があるものを再考してください。

于 2008-12-08T12:52:37.070 に答える
2

ここには、何が問題なのかを伝えるのに十分なコードがありません。前述のようにボトルネックになる可能性がありますが、それが発生するには、少なくとも 1 つのスレッドが実行されている必要があります (CPU 使用率がかなり高い状態)。そうしないと、ロックを保持しているスレッドがロックを解放せずにスリープ状態になります。

デッドロックも別の可能性ですが、その場合は複数のスレッドで 2 つの個別のロックを同期する必要があり、ここでは 1 つのロック オブジェクトのみを示しています。

これ以上の情報なしに判断することは本当に不可能です。

于 2008-12-08T15:03:35.763 に答える
2

String で同期する必要がある場合は、String インスタンスをミューテックスとして使用しないでください (インターンされているかどうかに関係なく)。ただし、文字列を使用して適切なミューテックス オブジェクトを作成できます: ID で同期します

于 2008-12-08T13:07:31.923 に答える
1

デッドロックが発生している可能性が非常に高いです。

デッドロックを回避したい場合は、すべてのスレッドが常に同じ順序でロックを取得する必要があります。String.intern() を使用してロックを取得すると、JVM 全体の任意のコードがアクセスできるインスタンスをロックし、ロックします。ほとんどの場合、独自のコード内の他のスレッドがデッドロックしていますが、そうである必要はありません。

「key.intern() 一意性を保証する」という回答の意味がわかりません。このintern()メソッドは、同等のすべての文字列に対して同じオブジェクトを返すことにより、一意性を減らします。

  String s1 = new String(new char[] { 'c', 'o', 'm', 'm', 'o', 'n' }).intern();
  String s2 = new String("commo" + (s1.charAt(s1.length() - 1)).intern();
  String s3 = "common";
  if ((s1 == s2) && (s1 == s3))
    System.out.println("There's only one object here.");

上記のコードは、2 つの一意のインスタンスを作成したにもかかわらず、それらをインターンすることによって、それらを 1 つの正規のインスタンスに置き換えたことを示しています。

独自のコードの外で見えるオブジェクトをロックとして使用するときは常に危険です。プライベート メンバー、独自のスタックからのエスケープを許可しないオブジェクトなどに固執するようにしてください。

于 2008-12-11T05:34:27.500 に答える
1

Bombe が言うように、 key.intern() は、同期するための非常に一意のキーを必ずしも提供するとは限りません。

ただし、コードの変更には注意が必要です。コードを変更する前に、コードのロック戦略を理解する必要があります。intern() 呼び出しを削除すると、正しく動作しているように見えるコードが得られる可能性がありますが、後で噛み付くデータ競合が含まれています。

于 2008-12-08T11:26:00.583 に答える
-1

String.intern() はネイティブ メソッドです。これが問題の原因である可能性があります。

于 2008-12-08T11:09:47.653 に答える
-1

key.intern() は文字列定数プールから文字列を返すため、key.intern() は一意性を保証します。

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#intern() インターン

public String intern() 文字列オブジェクトの正規表現を返します。最初は空である文字列のプールは、クラス String によってプライベートに維持されます。

于 2008-12-08T09:43:48.263 に答える