2012-03-04 24 views
2

次のコードを可能な限り同時に動かすことができないため、Javaで非常に失望しています。同期がない場合、2つのスレッドはより頻繁に切り替えられますが、同期メソッドにアクセスしようとすると、2番目のスレッドがロックを取得するまでに(30秒のように)時間がかかりすぎ、最初のスレッドがロックを取得する前に2番目からJavaのスレッド/同期

public synchronized static void i() 
    { 

    System.out.println(Thread.currentThread().getName()); 

    } 
    public static void main(String[] f) 
    { 

    Thread t = new Thread(new Runnable(){ 
    public void run() 
    { 
     while(true) 
     i(); 
    }}); 
    t.setName("a: "); 
    Thread t2 = new Thread(new Runnable(){ 
    public void run() 
    { 
     while(true) 
     i(); 
     }}); 
     t2.setName("b: "); 
     t.start(); 
     t2.start(); 

    } 

答えて

7

公正性をtrueに設定してReentrantLockを使用してください。

public static final ReentrantLock lock = new ReentrantLock(true); 
public static void i() 
{ 
    lock.lock(); 
    try { 
     System.out.println(Thread.currentThread().getName()); 

    } finally { 
     lock.unlock(); 
    } 
} 
+2

exabrialとChikeiの答えを組み合わせると、正解が正解になります。 exebrialが指摘した理由のため、公平性はデフォルトで保証されません。しかし、インタリーブに関しては、私はChikeiの提案にいくらか公平な保証をするロックを使うことになるでしょう。 '完全な'インターリーブが必要な場合、つまりスレッドBは常にスレッドAの後に実行され、スレッドAが再び実行される前に、別のロック方式が必要です。 – brettw

+0

ありがとう、どちらの方法もうまくいくようです –

3

問題はJavaではなく、あなたのコードです。ロック契約のどの部分が公正な買収を意味するのか?既存のロックホルダーをそのまま使用できるようにするには、はるかに高速で効率的です。通常、彼らは仕事を終えて、とにかくロックを解除します。あなたのプログラムは、ロックとスレッドインターリーブの公平性について0の仮定をするべきです。

公正なインターリーブが必要な場合は、同期メソッドを使用しないでください。プライベートオブジェクトを作成し、そのプライベートオブジェクトに対してwait()およびnotify()メソッドを手動で使用してインターリーブを強制する必要がありますが、それでも仮定します:)フェアインターリーブを取得するには、 volatile実行する人のターンを示す条件変数。

+0

優れているこの作品は完璧です –