2

I have a pretty simple problem, in wich I try to exchange an object ( in this case an array of int) between two task : Producer and Consumer. The Producer class produces an array of int and than it tries to exchange it with the Consumer array ( which is an empty array) using an Exchanger object. But it seems that it doesn't work: when the Consumer tries to print the array, it gets nothing.

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();
}

If i uncomment the lines in Producer i see that the numbers generated are still there. So why does it not exchange the object?

paradigmatic
  • 40,153
  • 18
  • 88
  • 147
Daniel S.
  • 151
  • 2
  • 8
  • Wait: so you have a Producer, a Consumer and an Exchanger, all of which you wrote yourself; and the Exchanger seems not to be working; so you show us the Producer, the Consumer but **not** the Exchanger? – Karl Knechtel Aug 14 '11 at 14:55
  • The Producer, Consumer, and the RandomGenerator.Integer classes I wrote myself but, the Exchanger class is implemented in the java library: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html#exchange(V) – Daniel S. Aug 14 '11 at 14:57

2 Answers2

4

The exchanger does not swap the references in place, but returns the exchanged object. So you should write something like:

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

BTW, I don't think exchangers are appropriate for producer/consumers...

paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • That was one of the problems. I also had to change the ArrayList into a CopyOnWriteArrayList – Daniel S. Aug 14 '11 at 15:18
  • 1
    @Joordy if you still need a synchronized list (CopyOnWriteArrayList), you are still doing something very wrong. You are not using Exchanger correctly still. Exchanger and synchronized list are two exclusive methods. – toto2 Aug 14 '11 at 15:32
  • @paradigmatic I would also think Exchanger not appropriate for producer/consumer, but it is the example they give in the [api](http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Exchanger.html). – toto2 Aug 14 '11 at 15:34
0

The exchange isn't magical; the Exchanger object can't replace the object references itself. The documentation tells us that calling the function returns the object that was provided by the other thread, once the exchange point was reached, which is how we "receive" it. I haven't actually done any of this, but I assume you're meant to assign this result back; i.e. ints = exchanger.exchange(ints); in both classes.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153