views:

40

answers:

2

My task was to deal with problem of 5 eating thinkers. Each of them can eat only 10 times. Solution should base on Semaphore. I almost solved the task and output was correct when I simply used println for showing state of each thinker. But there is additional point to store those states in some sort of collection. And somehow I can't make it work. Now my Vector stores only first iteration of loop. What am I doing wrong ? Vector is static so it should work ok.

import java.util.concurrent.Semaphore;
import java.util.Random;
import java.util.Vector;

public class Thinker extends Thread
{
    private static final Random rand = new Random();
    private static int event=0;
    private int id;
    private Semaphore sem;
    private static Vector<Object[]> vector = new Vector<Object[]>();

    public Thinker(int i, Semaphore s)
    {
        id = i;
        sem = s;
    }

    private void busy()
    {
        try
        {
            sleep(rand.nextInt(1000));
        } catch (InterruptedException e){}
    }

    private void thinking()
    {
        String str = "Thinker " + id + " is thinking";
        vector.add( this.addToObject(System.currentTimeMillis(), event , str) );
        event++;
        busy();
    }

    private void eating()
    {
        String str ="Thinker " + id + " is hungry and is trying to pick up his chopsticks";
        vector.add( this.addToObject(System.currentTimeMillis(), event , str) );
        event++;
        busy();
        str = "Thinker " + id + " is eating";
        vector.add( this.addToObject(System.currentTimeMillis(), event , str) );
        event++;
        busy();
        str = "Thinker" + id + " finished eating, and puts away his chopsticks";
        vector.add( this.addToObject(System.currentTimeMillis(), event , str) );
        event++;
    }

    private Object[] addToObject(long t, int i,String s ){
        Object[] o = new Object[4];
        o[3] = s;
        o[2] = i;
        o[1] = "00000";
        o[0] = t;
        return o;
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 10; ++i)
        {
            thinking();
            try
            {
                sem.acquire();
            } catch (InterruptedException e){}
            eating();
            sem.release();
        }
    }

    public static void main(String[] args)
    {
        final int N = 5;
        Semaphore sem = new Semaphore(N, true);
        Thinker[] thinker = new Thinker[N];

        for (int i = 0; i < N; i++)
        {
            thinker[i] = new Thinker(i, sem);
            thinker[i].start();
        }

        System.out.println("vctr size; "+vector.size());

        for (int i = 0; i < vector.size(); i++) {
            System.out.println();
            Object[] o = vector.get(i);
            System.out.printf("%d %d %s %s\n", o[0], o[2], o[1], o[3]);

        }
    }
}

Output i should get :
1202393057117 1 OOOOO Thinker 1 is thinking
1202393057117 2 OOOOO Thinker 3 is thinking
1202393057118 3 OOOOO Thinker 0 is thinking
1202393057118 4 OOOOO Thinker 2 is thinking
1202393057118 5 OOOOO Thinker 4 is thinking
1202393057118 6 OOOOO Thinker 0 is hungry and is trying to pick up his chopsticks
1202393057119 7 lOOOO Thinker 0 is eating
1202393057119 8 OOOOO Thinker 0 finished eating
1202393057119 9 OOOOO Thinker 0 is thinking
1202393057119 10 OOOOO Thinker 0 is hungry and is trying to pick up his chopsticks
1202393057126 11 lOOOO Thinker 0 is eating
1202393057126 12 OOOOO Thinker 0 finished eating

A: 

Your main method exits before the any/all of the Threads do their thing, it does not wait for them.

I've had to deal with a similar problem on several occasions, and I'm a big fan of CountDownLatch. I'll provide an example how it can help, not saying this is the only/right way.

In this particular example, you could define:

private static CountDownLatch latch;

In your main, instantiate it with the number of threads you are using:

latch = new CountDownLatch(N);

Right before your threads' run() finishes, do:

latch.countDown();

Again, in your main, before trying to print the vector's contents:

latch.await();

(deal with InterruptedException as you best see fit).

The latch.await() will block your main thread until all of the other threads are done, and you'll have your states recorded.

More: http://java.sun.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html

Lauri Lehtinen
haven't heard about that, will check later. Thanks !
terence6
A: 

Let the Thinkers finish their meal before trying to display the states.

...
/* Start the thinkers... */
for (int i = 0; i < N; i++) {
  thinker[i] = new Thinker(i, sem);
  thinker[i].start();
}
/* Wait for them to finish... */
for (int i = 0; i < N; i++) {
  try {
    thinker[i].join();
  } catch(InterruptedException ex) {
    return;
  }
}
...
erickson
could you take me through logic of your solution ? when thinker joins ? after the thread has ended ?
terence6
@terence6 - yes, a call to `join()` will block the caller until the thread (Thinker) dies. If it's already dead when `join()` is called, it's a no-op.
erickson