2009-05-19 2 views
4

synchronized(x) { }を避けながら、複数のスレッドが同じ日付を更新する更新プログラムの問題を回避できるかどうかは疑問です。同期を直接使用せずにJavaで更新が失われないようにする

私は、多くのことになるだろうが追加され、単位:

val++; 
ary[x] += y; 
ary[z]++; 

私はJavaのバイトコードにこれらをコンパイルする方法を知っていないと、スレッドはバイトのこれらのステートメントブロックの1つの途中で中断することができればコード。言い換えれば、これらのステートメントはスレッドセーフですか?

また、私はVectorクラスが同期されていることを知っていますが、その意味がわかりません。位置iの値がvec.get(i)vec.set(...)の間で変更されないという点で、次のコードはスレッドセーフであるでしょうか。

class myClass { 
    Vector<Integer> vec = new Vector<>(Integer); 

    public void someMethod() { 
    for (int i=0; i < vec.size(); i++) 
     vec.set(i, vec.get(i) + value); 
    } 
} 

ありがとうございます。

答えて

6

スレッディングの目的で、+++=は2つの操作(doublelongの4つ)として扱われます。したがって、更新は互いに矛盾してしまう可能性があります。 1つだけでなく、間違ったタイミングで動作するスケジューラが、数ミリ秒の更新をなくすことができます。

java.util.concurrent.atomicはあなたの友人です。

あなたのコードは個別に更新する各要素を気にしない、あなたを想定し、安全に行うことができ、あなたのサイズを変更しない、と(!):

for (int i=0; i < vec.size(); i++) { 
    synchronized (vec) { 
     vec.set(i, vec.get(i) + value); 
    } 
} 

あなたにリサイズ追加したい場合Vector​​ステートメントをforループの外側に移動する必要があります。また、単純な新しいArrayListを使用することもできます。実際には、同期されたリストのための多くの使用はありません。

しかし、もしあなたがAtomicIntegerArrayを使用することができます(!)なしロックなしボクシングの利点を持っている

private final AtomicIntegerArray ints = new AtomicIntegerArray(KNOWN_SIZE); 
[...] 
    int len = ints.length(); 
    for (int i=0; i<len; ++i) { 
     ints.addAndGet(i, value); 
    } 
} 

。実装は非常に面白く、さらに複雑な更新(乱数ジェネレータなど)を行う必要があります。

+0

ありがとう、java.util.concurrent.atomicが存在しませんでした。 – nash

+0

これは低レベル側のビットです。 java.util.concurrentは、より一般的には有用なレベルです。 –

1

vec.set()とvec.get()は、他のスレッドでセットや取得を失うような方法で値を設定したり取得したりしないので、スレッドセーフです。 ではなく、は、あなたのセットとあなたのゲットが中断することなく行われることを意味します。

上記の例のように実際にコードを書くつもりなら、おそらく何かをロックするべきでしょう。そしてsynchronized(vec) { }はどんなに良いものでもあります。 2つのスレッドセーフな操作だけでなく、2つの操作を同期させることをここで求めています。

java.util.concurrent.atomicでさえ、1つの操作(getまたはset)が安全に行われることを保証します。 1回の操作で増分する必要があります。

+0

getAndIncrementなどと似ていますか?技術的には複数の操作として実装されていますが、失敗した場合はループします。 –

関連する問題