2

Producer と Consumer の 2 つのタスク間でオブジェクト (この場合は int の配列) を交換しようとする、非常に単純な問題があります。Producer クラスは int の配列を生成し、それを Exchanger オブジェクトを使用して Consumer 配列 (空の配列) と交換しようとします。しかし、うまくいかないようです: Consumer が配列を出力しようとしても、何も得られません。

public class Producer implements Runnable{
private Exchanger<List<Integer>> exchanger;
private List<Integer> ints = new ArrayList<Integer>();

public Producer(Exchanger<List<Integer>> ex) {
    this.exchanger = ex;
}

public void run() {
    RandomGenerator.Integer gen = new RandomGenerator.Integer();
    try{
    while(!Thread.interrupted()) {
        for (int i = 0;i < Test.LIST_SIZE;i++) 
            ints.add(gen.next());
        exchanger.exchange(ints);
        //for(Integer x : ints) 
            //System.out.print(" " + x);
        //System.out.println();
    }
    }catch(InterruptedException e) {
        System.out.println("Producer interrupted");
    }
}
}


public class Consumer implements Runnable {
private Exchanger<List<Integer>> exchanger;
private List<Integer> ints = new ArrayList<Integer>();

public Consumer(Exchanger<List<Integer>> ex) {
    this.exchanger = ex;
}

public void run() {
    try{
    while(!Thread.interrupted()) {
        exchanger.exchange(ints);
        System.out.println("Consumer:");
        for(Integer x : ints) {
            System.out.print(" " + x);
            ints.remove(x);
        }
        System.out.println();
    }
    } catch(InterruptedException e) {
        System.out.println("Consumer interrupted");
    }
}
}


public class Test {
public static final int LIST_SIZE = 10;

public static void main(String[] args) throws InterruptedException {
    ExecutorService exec = Executors.newCachedThreadPool();
    Exchanger<List<Integer>> exchanger = new Exchanger<List<Integer>>();
    exec.execute(new Producer(exchanger));
    exec.execute(new Consumer(exchanger));
    TimeUnit.MILLISECONDS.sleep(5);
    exec.shutdownNow();
}

Producer で行のコメントを外すと、生成された数値がまだそこにあることがわかります。では、なぜオブジェクトを交換しないのでしょうか?

4

2 に答える 2

4

エクスチェンジャーは参照をその場で交換しませんが、交換されたオブジェクトを返します。したがって、次のように書く必要があります。

List<Integer> received = exchanger.exchange(ints);
System.out.println("Consumer:");
for(Integer x : received) {
    System.out.print(" " + x);
        ...
}

ところで、エクスチェンジャーはプロデューサー/コンシューマーには適していないと思います...

于 2011-08-14T15:03:00.437 に答える
0

交換は魔法ではありません。Exchanger オブジェクトは、オブジェクト参照自体を置き換えることはできません。ドキュメントによると、関数を呼び出すと、交換ポイントに到達すると、他のスレッドによって提供されたオブジェクトが返されます。これが、オブジェクトを「受け取る」方法です。私は実際にこれを行ったことはありませんが、この結果を元に戻すことを意図していると思います。つまりints = exchanger.exchange(ints);、両方のクラスで。

于 2011-08-14T15:15:07.787 に答える