Java 生产者线程被卡住,但没有阻塞

Java 生产者线程被卡住,但没有阻塞,java,multithreading,consumer,producer,Java,Multithreading,Consumer,Producer,我有一个生产者-消费者线程集,但根据JConsole堆栈跟踪,生产者被卡在了一行不是.put()的代码上 class Producer implements Runnable { private final BlockingQueue<CopyOnWriteArrayList<Creature>> queue; private World myWorld; Producer(BlockingQueue<CopyOnWriteArrayLis

我有一个生产者-消费者线程集,但根据JConsole堆栈跟踪,生产者被卡在了一行不是
.put()
的代码上

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! ******************************");
                }
            }
        }
    }
}
第25行是
而(true){
行。

getTick()
thread safe(线程安全)?即,在到达刻度值的过程中是否存在同步关键字、某种形式的锁、易失性读取或原子变量?如果没有,线程可能看不到对刻度计数器进行的并发更改。中断和调试可能会迫使这些更改可见

此外,您的制作人似乎不应该等待成功的
queue.put()
,而是等待应用程序前进到下一个刻度。
myWorld.myApp.getTick()
阻塞?否则,您的代码将无休止地循环,除非:

  • 还有其他线程同时修改勾号
  • 你的线程被挂起,另一个被唤醒的线程修改勾号
只有在可能发生变化的情况下,使用无休止的循环检查条件的变化(也称为轮询/旋转等待)才有意义


我建议实现一个阻塞并安全发布
waitForTick(int-tick)
在对象
myWorld.myApp
中。除了线程安全集合之外,还有其他可用于同步不同线程的并发组件,如信号量、屏障等。

您使用的是哪种阻塞队列实现?我已经尝试了
ArrayBlockingQueue
LinkedBlockingQueue
,它可以挂起。请将(JConsole)堆栈跟踪添加到您的问题中。您确定执行路径到达了
put
行吗?在
put
行周围有条件语句(if/for)。是的,我非常确定。每当我在该行调试和中断,并手动推进它时,条件语句(if)的计算结果为true(无需我做任何其他事情),我可以手动退出代码。getTick()线程安全吗?否。它只返回
int
变量,该变量在每次单独的主线程(游戏控制器)运行时inc'd+1循环迭代。主线程是唯一一个修改
int
勾号的线程。每当我调试和中断时,
getTick
值都会增加到足以满足if语句的程度。生产者线程总是在该条件语句上循环,所以我不明白为什么它最终不会看到更改t
getTick()。
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)