-2

3 つのスレッドを持つアプリケーションを開発しています。それらをa、b、cと呼びましょう。

今、私はこのようなものを開発しなければなりません。

最初に b は a がそのタスクを完了するのを待ち、c は b を待ちます。

「a」がタスクを終了するとすぐに「b」に通知します。'b' が起動するはずです。ここで「a」は待機状態になります。'a' は、'c' から確認応答を受け取るまで待機します。

b はタスクを終了し、'c' に通知します。ここで、'c' がウェイクアップし、'b' が待機状態になります。

ここで、c はタスクを終了し、'a' に確認応答します。ここで 'c' は待ちます。

これは循環プロセスであり、 a -> b 、 b -> c、 c->a から続きます

このサイクルの間に、すべてのスレッドがデータ転送のためにキューにアクセスします。つまり、「a」はデータをキュー q1 に入れ、「b」はデータをフェッチして別のキュー q2 に入れ、「c」は q2 からフェッチして処理し、「a」に返します。

この機能の実装中に立ち往生しています。これを行う方法について何か考えはありますか?

ありがとう...

4

3 に答える 3

1

キューの使用が許可されている場合(宿題のようです)、よりエレガントなことができます。おそらく結果として得られる内部ロックは、セマフォを使用したソリューションに似ていますが、より洗練されています。

プロセスのペアごとに 1 つずつ、3 つのキューを作成します。実際のデータは送信せず、開始の信号のみを送信します。

Queue<Integer> queueA2B = new BlockingQueue<Integer>();
Queue<Integer> queueB2C = new BlockingQueue<Integer>();
Queue<Integer> queueC2A = new BlockingQueue<Integer>();

// initialize only the queue that *feeds* A:

queueC2A.put(1);

各プロセスは、キューからアイテムを取得し、そのプロセスを実行して、次のプロセスにシグナルを送信する必要があります。例 A:

while (...) {
   queueC2A.take(); // this will block until there's something in the queue
   // do my stuff
   queueA2B.put(1); // send "signal" to the next process
}
于 2012-08-21T10:46:18.867 に答える
0

私はセマフォでそれを行います。スレッドは独自のセマフォを必要としており、終了すると次のセマフォを解放します。もちろん、これはモニターでも実行できます ( Object#wait() and Object#notify())。それらが循環的に実行されるようにするには、単純に無限ループで実行させ、セマフォがいっぱいになるのを待ちます。

import java.util.concurrent.Semaphore;

public class Main {
    private Semaphore a = new Semaphore(1), b = new Semaphore(0), c = new Semaphore(0);

    public class A implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    a.acquire(1);
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("performing task A");
                    b.release(1);
                } catch (InterruptedException e) {}
            }
        }
    }

    public class B implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    b.acquire(1);
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("performing task B");
                    c.release(1);
                } catch (InterruptedException e) {}
            }
        }
    }

    public class C implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    c.acquire(1);
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("performing task C");
                    a.release(1);
                } catch (InterruptedException e) {}
            }
        }
    }

    public void startThreads() {
        new Thread(new A()).start();
        new Thread(new B()).start();
        new Thread(new C()).start();
    }

    public static void main(String[] args) throws InterruptedException {
        Main ld = new Main();
        ld.startThreads();
    }
}

モニターとは対照的に、このソリューションの優れた点は、外側からセマフォを埋めるだけで、2 番目の「スレッド ワーム」を開始して円を描くように実行できることです。

于 2012-08-21T10:31:12.657 に答える
0

良い質問です。セマフォを使用してスレッドをシーケンスで実行する方法を示す小さなクラスを作成しました。お役に立てれば:

public class LockingDemo{

    private Semaphore a = new Semaphore(0);
    private Semaphore b = new Semaphore(0);
    private Semaphore c = new Semaphore(1);

    class A implements Runnable{
        @Override
        public void run() {
            try {
                c.acquire(1);
                System.out.println("Doing A");
                a.release(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class B implements Runnable{
        @Override
        public void run() {
            try{
                a.acquire(1);
                System.out.println("Doing B");
                b.release(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class C implements Runnable{
        @Override
        public void run() {
            try{
                b.acquire(1);
                System.out.println("Doing C");
                c.release(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }



    public void a() throws InterruptedException{
        new Thread(new A()).start();
    }

    public void b() throws InterruptedException{
        new Thread(new B()).start();
    }

    public void c() throws InterruptedException{
        new Thread(new C()).start();
    }

    public static void main(String[] args) throws InterruptedException {
        LockingDemo ld = new LockingDemo();
        System.out.println("FIRST RUN CALLING B -> A -> C");
        ld.b();
        ld.a();
        ld.c();
        Thread.currentThread().sleep(2000);
        System.out.println("SECOND RUN CALLING C -> B -> A");
        ld.c();
        ld.b();
        ld.a();
    }
}

これが出力です

FIRST RUN CALLING B -> A -> C
Doing A
Doing B
Doing C
SECOND RUN CALLING C -> B -> A
Doing A
Doing B
Doing C
于 2012-08-21T10:15:26.083 に答える