2012-05-08 5 views
1

私は並行処理のプログラミングに錆びており、誰かが私が評価している並行処理パターンについていくつかの洞察を提供できることを願っています。同時実行パターン:特定の条件の下でブロックと非ブロックを切り替えるオブジェクト

アイデアは、大部分の時間、ノンブロッキングモードで動作するオブジェクトがあることです。しかし、ある条件下では、オブジェクトが同期して動作することを要求するメソッドが呼び出されます。

以下は、問題を説明するために私がスケッチしたJavaコードのサンプルです。

考えられるのは、複数のスレッドがSyncMethod()というこの1つのメソッドを除いて、このオブジェクトのすべてのメソッドを安全に呼び出すことができるという考えです。このメソッドは特定の条件の下で呼び出され、このような場合は、スレッドを同期クリティカルコードパスにリダイレクトする必要があるSyncAsyncMethod()などのメソッドがあります。これを容易にするために、状態を追跡するための原子変数と、非同期セクションで実行されるスレッドの数を格納します。

私は同時実行プログラミングを行っているので、しばらく経っています。論理を複雑にすることや競合状態を見落としている場合は、教えてください。

また、すべての方法を同期させるよりもパフォーマンスを向上させるには、このすべてのロジックが価値があるとも考えています。 Atomic変数のチェックが高価であるかどうかは誰にも分かりますか?

最後に、このパターンの名前があるかどうかわかりますか?

おかげで、あなたが読んだとき {

private AtomicBoolean mSyncMode; 
private AtomicBoolean mOutOfAsyncZone; 
private AtomicInteger mAsyncThreads; 

public MyObject() 
{ 
    mSyncMode.set(false); 
    mOutOfAsyncZone.set(false); 
    mAsyncThreads=0; 
} 

//this method must always run synchronized... 
public synchronized void SyncMethod() 
{ 
    if(!mSyncMode.get()) 
     SetSyncMode(true); 

    if(mSyncThreads > 0) 
     wait(); 

    //do stuff.... 

    SetSyncMode(false); 
} 

//this method is used to toggle this object between sync and async mode. 
public void SetSyncMode(boolean b) 
{ 
    mSyncMode.set(b); 
} 

public void DoStuff() 
{ 
    //do stuff... 
} 

public void DoOtherStuff() 
{ 

} 

//this method can run safely 
public void SyncAndAsyncMethod() 
{ 
    if(mSyncMode.get()) 
    { 
     synchronized(this) 
     { 
      if(mAsyncThreads > 0) 
       wait(); 

      DoStuff(); 
     } 
    } 
    else 
    { 
     mAsyncThreads++; 
     DoStuff(); 
     mAsyncThreads--; 

     if(mSyncMode.get() && mAsyncThreads <= 0) 
     { 
      synchronized(this) 
      { 
       notifyAll(); 
      } 
     } 
    } 
} 

}

+0

ディラン、私は書式を編集して修正しようとしましたが、少なくとも6つの空白以外の文字である必要があります。最初と最後の行を4スペース分インデントします。 – Brady

+0

この質問は[コードレビュー](http://codereview.stackexchange.com/)に適しています。 – assylias

+0

私はEclipseでインデントを修正しました...私はもともとテキストパッドでこれをハッキングしました。 –

答えて

1

java.util.concurrent.locks.ReadWriteLockを使用してください。すべての 'non-blocking'メソッドはreadLock()を使用できます(ReadWriteLockは複数の読み取りロックを許可するためブロックされません)。もう1つのメソッドはwriteLock()を使用できます。

+0

それを得ましたが、読み込みロックが取得される前にすべての読み込みロックが解放されるまで、writelockは待機しますか?それ以外の場合は、ブロッキングメソッドの実行中に非ブロッキングメソッドがメソッド内で実行されているプロセスの末尾にある可能性があります。また、AtomicBooleanの条件付きテストと比較して、readlock()およびreadunlock()メソッドのコストについての洞察はありますか? –

+0

java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock.lock()のjavadocから: '読み書きロックが他のスレッドによって保持されていなければ、書き込みロックを取得します。スピードは分かりませんが、心配している場合はテストしてください。 – artbristol

+0

通常、**すべての** ReadLockが解放されるまで、WriteLockの呼び出しはブロックされ、WriteLockが解放されるまでReadLocksはブロックされます。複数のReadLockが同時に取得できます。つまり、1つのReadLockは別のReadLockをブロックしません。 – Brady

0

通常この動作を持つことができますMyObjectに -Dylan

パブリッククラス - 同期しない、書き込み - 同期させます。たとえば、コレクションがあり、読み取りのために同期せずにアクセスし、書き込みのときに同期する必要があります。

この場合、CopyOnWriteArrayListをコレクションとして使用できます。それはどんな同期もしません。更新すると、リスト全体が新しい参照に置き換えられます。それがこの状況へのアプローチです。

私はあなたの質問に答えることはできません。なぜあなたは同期する必要がないのかを指定してください。理由は何ですか? SyncAndAsyncMethod()方法で

+0

ユースケースについて質問していますか?私が念頭に置いていた1つの具体的なユースケースは、Javaで可能な限り速い倍精度バッファを作成することでした。私はダブルバッファを非同期に実行できるという考えですが、スワップ時にバッファを同期させる必要があります。しかし、私はこれをデザインパターンという意味でもっと考えています。 –

+0

参照置換はよりも使用できます。あなたは一次と二次のバッファを持っています。スワップはセカンダリのリファレンスを最初に設定し、最初に新しいものを作成します。これはより速いアプローチでなければなりません。 CopyOnWriteArrayListに実装されているのと同じです。 – alexey28

0

より良いアプローチは、この記事のように、条件変数を使用することです:

What is a Condition Variable in java?

+0

リファレンスコードがちょっと混乱していました。あなたは、(mSyncMode.get()&& mAsyncThreads <= 0){}をCondition.signal()で置き換え、(もし)の代わりにSyncMethod()のCondition.await mSyncThreads> 0)wait();? –

+0

ええ、私はちょっと混乱していると思います。アイデアは、OS/JVMが待機を管理し、おそらくスレッドを生成させることです。あなたの質問に対する答えははいです。提案したコードの変更を提案しています。私の回答に記載されているように、条件JavaDocを必ず読んでくださいhttp://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html – Brady

関連する問題