質問

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.

役に立ちましたか?

解決

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top