0

I have a producer-consumer set of threads, but the producer is getting stuck on a line of code that isn't the .put(), according to the JConsole stack trace.

class Producer implements Runnable {
    private final BlockingQueue<CopyOnWriteArrayList<Creature>> queue;
    private World myWorld;

    Producer(BlockingQueue<CopyOnWriteArrayList<Creature>> q, World myWorld) {
        queue = q;
        this.myWorld = myWorld;
    }

    public void run() {
        int nextTick = myWorld.myApp.getTick(); //'tick' is the current frame our main loop is on.      
        while (true) {
            if (myWorld.myApp.getTick() >= nextTick) { //if our world has updated to the next frame…
                nextTick = myWorld.myApp.getTick() + 1; //increment the next frame to wait for

                try {
                    for (int i = 0; i < myWorld.getCellController()
                            .getColumns(); i++) {
                        for (int j = 0; j < myWorld.getCellController()
                                .getRows(); j++) {

                            queue.put(myWorld.getCellController().Cells.get(i)
                                    .get(j));
                        }
                    }
                } catch (InterruptedException ex) {
                    System.out.println("INT! ******************************");
                } catch (NullPointerException ex) {
                    System.out.println("NULL! ******************************");
                } catch (ClassCastException ex) {
                    System.out.println("CAST! ******************************");
                } catch (IllegalArgumentException ex) {
                    System.out.println("ARG! ******************************");
                }
            }
        }
    }
}

According to the stack trace, it just stays on the while(true) line, without advancing through the loop, even though it should.

Stack trace:
Name: Producer
State: RUNNABLE
Total blocked: 0  Total waited: 196,958

Stack trace: 
concurrency.Producer.run(Setup.java:25)
java.lang.Thread.run(Thread.java:680)

Line 25 is the while(true) { line.

honkbert
  • 135
  • 1
  • 7
  • Which implementation of blocking queue are you using? – Perception Feb 17 '13 at 05:02
  • I've tried both `ArrayBlockingQueue` and `LinkedBlockingQueue`, it hangs with both. – honkbert Feb 17 '13 at 05:06
  • Please add the (JConsole) stack trace to your question. – Perception Feb 17 '13 at 05:11
  • Are you sure the execution path reached the `put` line? There are conditional statements(if/for) surrounding the `put` line – ericson Feb 17 '13 at 05:19
  • Yes, I'm fairly sure. Whenever I debug and break at that line, and manually advance it, the conditional (if) evaluates true (without me needing to do anything else), and I can manually step down the code just fine. – honkbert Feb 17 '13 at 05:34
  • Infinite loop because nextTick is > getTick() after the first run. – jdb Feb 17 '13 at 05:40
  • @jdb, see my comment below to Pyranja's answer. The "tick" is always being incremented by another thread. – honkbert Feb 17 '13 at 05:47
  • Your producer thread apparently does not see the value change. When you debug it does. Quickest fix- make the thing inside getTick volatile. – jdb Feb 17 '13 at 05:53
  • Thanks! That definitely did something... the producer isn't hanging anymore. – honkbert Feb 17 '13 at 06:04

1 Answers1

0

Is getTick() thread safe? I.e. is there a synchronized key word, a lock of some form, a volatile read or an Atomic variable on the way to the tick value? If not, your thread may not see concurrent changes made to the tick counter. Breaking and debugging may force these changes to be visible.

Additionally it seems like your producer should not wait for a successful queue.put(), but for the application to advance to the next tick. Is myWorld.myApp.getTick() blocking? If not, your code will just loop endlessly, unless :

  • There are other threads modifying the tick concurrently
  • Your thread is suspended and another awoken thread modifies the tick

Using an endless loop to check on changes of a condition (aka polling/spin waiting) only makes sense, if there is the possibility of changes.

I would suggest to to implement a blocking and safely publicating waitForTick(int tick) in the object myWorld.myApp. Apart from thread safe collections there are other concurrent components like Semaphores, Barriers etc. that can be used to synchronize different threads.

Pyranja
  • 3,529
  • 22
  • 24
  • Is `getTick()` thread safe? No. It simply returns `int` variable that is inc'd+1 every time the separate main thread (game controller) loop iterates. The main thread is the only thread that modifies the `int` tick. Whenever I debug and break, the `getTick` value is *way* increased enough to satisfy the if statement. The producer thread is always looping on that condition statement, so I don't get why it eventually never sees the change. – honkbert Feb 17 '13 at 05:46
  • Making the variable that `getTick()` returns `volatile` did the trick. – honkbert Feb 17 '13 at 07:55