0

私は間違いなく同時実行地獄にいます。私がやろうとしていることに対する良い/効率的な解決策を見つけることができません。テキスト ファイルを読み取り、その情報を共有 BlockedQueue に入れるプロデューサー スレッドがあります。また、共有 BlockedQueue を使用してデータを読み取り、データに対して重い処理を行う Consumer があります。StartPauseStopの 3 つのボタンを備えた GUI があります。

Producer と Consumer はどちらも Runnable を実装し、それぞれの計算に関する情報にアクセスするためのメソッドを提供します (たとえば、いくつかの統計やいくつかのオブジェクトを返します)。

[開始] オプションを使用して、Producer がファイルを開き、BlockedQueue へのデータの挿入を開始するようにします。また、コンシューマーはデータの取得を開始し、その計算を行います。

Pauseオプションを使用して、Producer がデータを BlockedQueue に入れるのを停止させたいのですが、同時に Producer のインスタンス変数にアクセスできるようにしたいと考えています。コンシューマについても同じことが言えます。私は重いことをやめたいと思っていますが、コンシューマで定義されたいくつかのインスタンス変数とメソッドにアクセスできるようにしたいと考えています。

停止オプションを使用して、プロデューサーとコンシューマーをリセットしたい...つまり、クリーンから開始するかのように。

私の質問は、これを効率的に実装する方法ですか? 特に一時停止を確認するには?

この擬似コードのようなものは効率的でしょうか?

Enum state;

class Producer implements Runnable {
    public List someList;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //put stuff into BlockedQueue
            }
            else if (state == Enum.stopped) {
               // reopen file and set state = running
            }


        }
    }
}

class Consumer implements Runnable {
    public Map someMap;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //start consuming from the BlockedQueue and do heavy computation
            }
            else if (state == Enum.stopped) {
               // clear stuff to start clean and set state = running
            }


        }
    }
}
4

2 に答える 2

1

私の質問は、これを効率的に実装する方法ですか? 特に一時停止を確認するには?この擬似コードのようなものは効率的でしょうか?

Consumerandでフィールドを使用することProducerは、これを行うための優れた方法だと思います。volatile列挙型への更新がスレッド間で適切に同期されるように、フィールドを確認する必要があります。または、synchronizedキーワードを使用する場合は、synchronizedいつ更新されるかが必要です。 volatileブロックする理由がないため、この場合はより適切です。

 public class Consumer {
    private volatile Enum state;
    ...
    if(state == Enum.paused) {

人々は解決策として「ポイズンピル」に言及しています。状態を変更するのは、オブジェクトをキューに入れるときです。このソリューションの問題は、コンシューマーがオブジェクトで作業している場合、キューをチェックしないため、これが機能しないことです。peek()キューでできると思いますが、stateフィールドは正常に機能するはずです。

Producer と Consumer は両方とも Runnable を実装し、それぞれの計算に関する情報にアクセスするためのメソッドを提供します (たとえば、いくつかの統計やいくつかのオブジェクトを返します)。

およびオブジェクトは引き続き存在し、アクセス可能になりますProducerConsumerいずれの場合も、スレッド間で共有されるフィールドに加えられた更新が適切に同期される必要があることを確認する必要があります。

私の質問は、これを効率的に実装する方法ですか? 特に一時停止を確認するには?

効率という点では、volatileフィールド アクセスは通常のフィールド アクセスよりも 100 倍程度遅くなるようです。すべての行に状態チェックを行うわけではありませんが、各処理ループの先頭でチェックするかif (loopCounter % 1000 == 0)、ループ全体で X 回ごとに一時停止をチェックするようなことを行うと、パフォーマンスがヒットしたかどうかはあまりわかりません。

于 2013-10-02T18:54:12.083 に答える