14

すべてのクラス バイト コードは、クラス ローダーごとに 1 回メモリにロードされることを学びました。つまり、あるスレッドが何らかのメソッドのバイト コードを実行しているときに、別のスレッドが実行されます。

1スレッド -> 1インスタンス -クラス Foo の == 問題ありません。

Xスレッド -> 1インスタンス -クラス Foo == の処理が必要 これは明らかです。

Xスレッド -> X それぞれのインスタンス -クラス Fooの == ????

メソッドで何も混乱していないことを確認する必要がありますか? メソッドがインスタンスレベルの変数を使用している場合、正しい変数を使用していると確信できますか?

アップデート:

私の質問が明確ではなかったようです。ここに数字の例があります

同期のないクラス型Fooのオブジェクトがあります!!

そのFooの 5 つのインスタンスがあり、それぞれに対して 5 つのスレッドが実行され、インスタンスレベルのパラメーターにアクセスします。たとえば、次のようになります。

class FOO {
     private SomeObject someObject=new SomeObject();

     private void problematicMethod(Data data) {
         someObject.doSomethingWithTheData(data);
         data.doSomethingWithSomeObject(someObject); 
// any way you want it use the data or export the data
     }
}

このクラスには1バイト コードしかなく、このバイト コードにアクセスするこのオブジェクトには5つのインスタンスしかないため、ここに問題があるのでしょうか。行う?

ありがとう、アダム。

4

5 に答える 5

14

すべてのクラス バイト コードは、クラス ローダーごとに 1 回メモリにロードされることを学びました。つまり、あるスレッドが何らかのメソッドのバイト コードを実行しているときに、別のスレッドが実行されます。

ここでは、クラスのロードとバイト コードは関係ありません。バイト コードは、JVM が解釈してネイティブ マシン コードにコンパイルする一連のアセンブリに似た命令です。複数のスレッドが、バイト コードにエンコードされた命令セットに安全に従うことができます。

1 スレッド -> 1 インスタンス - クラス Test の場合、問題ありません

おおむね正しい。スレッドが 1 つしかない場合は、すぐにスレッド セーフにする必要はありません。ただし、スレッド セーフを無視すると、成長と再利用性が制限されます。

X スレッド -> 1 つのインスタンス - クラス Test の処理が必要です。これは明らかです。

そうです、スレッドの可視性の理由と、重要な領域がアトミックに実行されるようにするために、同期またはロックの手法を使用することは非常に重要です。もちろん、それはすべてですよね?クラスに状態 (インスタンス変数またはクラス変数) がない場合は、スレッドセーフにする必要はありません (Java のExecutors, Arrays,Collectionsクラスのようなユーティリティ クラスを考えてください)。

X 個のスレッド -> X 個のそれぞれのインスタンス - クラス Test、????

各スレッドが Test クラスの独自のインスタンスを持ち、単一のインスタンスが複数のスレッド間で共有されていない場合、これは最初の例と同じです。Test のインスタンスが 2 つ以上のスレッドによって参照されている場合、これは 2 番目の例と同じです。

メソッドがクラス レベルの変数を使用している場合、正しい変数が使用されると確信できますか?

クラス変数staticは Java の変数です。synchronized複数のスレッドが同時にクラス変数を変更するのを防ぐために使用することの重要性を強調する2つの回答がすでに投稿されています。クラス変数の古いバージョンが表示されないようにするためのsynchronizedorの使用の重要性については言及されていません。volatile

于 2010-06-23T04:54:55.577 に答える
3

共有リソースで同期する必要があります。そのリソースがクラス レベルのフィールドである場合は、クラス自体で同期する必要があります。

public class Foo {
  private static int someNumber = 0;
  // not thread safe
  public void inc_unsafe()  { 
    someNumber++;
  }

  // not thread safe either; we are sync'ing here on an INSTANCE of
  // the Foo class
  public synchronized void inc_also_unsafe()  { 
    someNumber++;
  }

  // here we are safe, because for static methods, synchronized will use the class
  // itself
  public static synchronized void inc_safe()  { 
    someNumber++;
  }

  // also safe, since we use the class itself
  public static synchronized void inc_also_safe()  { 
    synchronized (Foo.class) {
      someNumber++;
    }
  }
}

{{java.util.concurrent}} は、Java の {{synchronized}} キーワードよりも多くの共有データを保護する方法を提供することに注意してください。それはあなたが望むものかもしれないので、それを調べてください。

( int インクリメントはすでにスレッドセーフであると主張したい人は、これは単なる例であり、基本的な概念は何にでも適用できることに注意してください。 )

于 2010-06-23T03:45:36.567 に答える
2

デイブの答えに加えて、異なる静的メンバーで機能する複数の静的メソッドがある場合は、別々の静的オブジェクトで同期することをお勧めします。

public class Foo {
  private static int someNumber = 0;
  private static int otherNumber = 0;
  private static final Object lock1 = new Object();
  private static final Object lock2 = new Object();

  public static void incSomeNumber() {
    synchronized (lock1) {
      someNumber++;
    }
  }

  public static void incOtherNumber() {
    synchronized (lock2) {
      otherNumber++;
    }
  }
}

このようにして、2つの異なるスレッドが、同期にとらわれることなく同時に呼び出すことができincSomeNumberますincOtherNumber


編集

これは。を使用した同じ例AtomicIntergerです。明示的なロックは必要ないことに注意してください。のすべてAtomicIntergerの操作はアトミックであり、ハードウェア操作を使用して実装されます。そのため、パフォーマンスが向上します。

import java.util.concurrent.atomic.AtomicInteger;

public class Foo {
  private static AtomicInteger someNumber = new AtomicInteger(0);
  private static AtomicInteger otherNumber = new AtomicInteger(0);

  public static int incSomeNumber() {
    return someNumber.incrementAndGet();
  }

  public static int incOtherNumber() {
    return otherNumber.incrementAndGet();
  }
}
于 2010-06-23T03:54:52.580 に答える
0

すべてのスレッドは同じクラスローダーに移動する必要があります。FOo.classを使用する10個のスレッド、10個すべてがまったく同じオブジェクトを持ちます。異なるクラスローダーで同じクラスを取得する唯一の方法は、

a)クラスローダーの魔法を実行する独自のコードを作成しました
b)戦争内と共有tomcat libフォルダー内の両方にコードを含めるなどの奇妙なことを実行しました...そして、イベントの正しいシーケンスを実行して、2つのコピーを作成しましたさまざまな場所からロードされます。

すべての通常の場合..クラスを作成すると、クラスオブジェクトのコピーが1つだけ存在し、(これで)すべての同期がアプリケーション全体で行われます。

于 2010-06-23T04:03:19.380 に答える
0

そして、ローカル変数としてのインスタンス変数は、各スレッドに固有のものだと思います。したがって、デフォルトではスレッドセーフです。ただし、同期によって処理する必要があります。

于 2013-08-31T11:55:10.500 に答える