2013-07-26 29 views
14

クラスの各インスタンスに、そのクラスのメソッドの独自のコピーがあるかどうかを知りたいですか?インスタンスのメソッドとインスタンス変数のスレッドセーフ

は、私は次のクラスMyClassを持っている、としましょう:各ユーザーを知ってい

MyClass instanceOfUser1 = new MyClass(); 
MyClass instanceOfUser2 = new MyClass(); 

彼のスレッドのコピーを持っている:2貴様のユーザーが同じようMyClassのインスタンスを作成している場合

public MyClass { 

    private String s1; 

    private String s2; 

    private String method1(String s1){ 
    ... 
    } 

    private String method2(String s2){ 
    ... 
    } 
} 

MyClassのメソッド?そうであれば、インスタンスメソッドだけがそれらを操作する限り、インスタンス変数はスレッドセーフです。

私はよくインスタンス変数がスレッドセーフではないので、この質問をしています。なぜ各ユーザーがnewオペレーターに電話をかけてインスタンスを取得するのか、そのようにすべき理由はわかりません。

+0

スレッドごとに異なるメソッドを持つ 'MyClass'のインスタンスまたは' MyClass'のインスタンスを持つ各スレッドについて質問していますか? – Jeffrey

+0

インスタンス変数は、本質的にスレッドセーフではありません。 2つのスレッドが同じオブジェクトへの参照を変更できる場合は、何らかの同期を実装する必要があります。 – Joel

+6

あなたは本当に混乱しています。スレッドセーフは状態に関するものです。状態はフィールドであり、メソッドではありません。クラスのスレッドセーフティは、メソッドによってフィールドs1とs2がどのように使用されているかによってまったく異なります。彼らの体を持っていないので、答えが不可能になります。 –

答えて

9

各オブジェクトはクラスのインスタンス変数のコピーを取得します。クラスのすべてのインスタンス間で共有される変数はstaticです。インスタンス変数がスレッドセーフである必要はないという理由は、非同期インスタンスメソッドを呼び出す複数のスレッドによって同時に変更される可能性があるからです。

class Example { 
    private int instanceVariable = 0; 

    public void increment() { 
     instanceVariable++; 
    } 
} 

2つの異なるスレッドが、あなたはデータ競合を持っている同じでincrementを呼び出す場合 - instanceVariableが戻って二つの方法の終わりに1または2インクリメントかもしれません。​​キーワードをincrementに追加するか、intなどの代わりにAtomicIntegerを使用してこのデータ競合を解消することができますが、各オブジェクトがクラスのインスタンス変数の独自のコピーを取得しているからといって、必ずしも変数スレッドセーフな方法でアクセスされます。これはクラスのメソッドによって異なります。 (例外はfinal不変変数であり、スレッドセーフな方法ではアクセスできません。シリアル化ハックのようなものではありません)

+2

まったく新しいインスタンスが各スレッドで使用されている場合、 'instanceVariable'フィールドが競合する読み取り/書き込みから安全でないと言うでしょうか?これはOPが話しているシナリオです、いいえ? –

2

複数のクラスからインスタンスにアクセスできる状況はたくさんあります。たとえば、インスタンスが別のクラスの静的変数である場合、すべてのスレッドはそのインスタンスを共有し、大きな問題になることがあります。それは私の心に浮かぶ最初の方法です...

5

主に静的変数とクラスのインスタンスで発生する問題同時にアクセスされる。

クラス内のメソッドは気にする必要はありませんが、フィールド(クラスレベルのスコープを意味します)の詳細については心配する必要はありません。クラスのインスタンスへの複数の参照が存在する場合、異なる実行パスが同時にインスタンスにアクセスしようとし、競合状態などの意図しない結果を引き起こす可能性があります。

クラスは、基本的にオブジェクトのインスタンスを作成するための青写真です。オブジェクトがインスタンス化されると、参照によってアクセスされるメモリ内の地点を受け取ります。複数のスレッドがこの参照へのハンドルを持っていると、同時にインスタンスにアクセスする場所が発生する可能性があります。これにより、両方のスレッドによってフィールドが操作されます。

4

'インスタンス変数はスレッドセーフではありません' - この文はコンテキストによって異なります。 例えば、あなたがサーブレットについて話しているのなら、それは本当です。サーブレットはインスタンスを1つしか作成せず、複数のスレッドがインスタンスにアクセスするためです。したがって、インスタンス変数はスレッドセーフではありません。

上記の単純化されたケースでは、スレッドごとに新しいインスタンスを作成する場合、インスタンス変数はスレッドセーフです。

ホープこれはあなたの質問

2

各インスタンスは、インスタンス変数の独自のセットを持って答えます。すべてのインスタンスにメソッドの個別のコピーがあるかどうかをどのように検出しますか?違いはインスタンス変数の状態を調べるだけでは見えませんか?

実際、いいえ、メソッドのコピーは1つだけです。つまり、メソッドの呼び出し時に実行される一連の命令です。しかし、実行時に、インスタンスメソッドは、それが呼び出されているインスタンスを予約識別子thisで参照できます。 thisという識別子は、現在のインスタンスを参照します。インスタンス変数(またはメソッド)を何か他のもので修飾しないと、thisが暗黙指定されます。例えば

setFlag()setAnotherFlag()方法のためのVM命令を構成するバイトのコピーは1つだけあります。しかし、呼び出されたときには、thisが呼び出しが発生したインスタンスに設定されます。 thisは修飾されていない変数に含意されているため、この例ではthisへの参照をすべて削除でき、まったく同じように機能します。

ただし、上記のfriend.flagのように変数が修飾されている場合は、別のインスタンスの変数を参照できます。これは、マルチスレッドプログラムで問題になる方法です。しかし、オブジェクトがあるスレッドから他のスレッドに見えるように「エスケープ」しない限り、心配することはありません。

4

methodは、指示のセットに過ぎません。どちらのスレッドがメソッドを呼び出しても、それらの命令のコピーを取得します。その後、実行が開始されます。この方法では、method and thread-scopedのローカル変数を使用したり、静的リソース、共有オブジェクト、または他のリソース(visible across threadsなど)などの共有リソースを使用することがあります。

関連する問題