【问题标题】:Producer thread getting stuck, but not blocking生产者线程卡住,但没有阻塞
【发布时间】:2013-02-01 19:22:45
【问题描述】:

我有一组生产者-消费者线程,但根据 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! ******************************");
                }
            }
        }
    }
}

根据堆栈跟踪,它只是停留在while(true) 行上,没有通过循环,即使它应该。

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)

第 25 行是 while(true) { 行。

【问题讨论】:

  • 您使用的是哪种阻塞队列实现方式?
  • ArrayBlockingQueueLinkedBlockingQueue 都试过了,都挂了。
  • 请将 (JConsole) 堆栈跟踪添加到您的问题中。
  • 您确定执行路径到达put 行吗? put 行周围有条件语句(if/for)
  • 是的,我很确定。每当我在该行进行调试和中断,并手动推进它时,条件 (if) 的计算结果为 true(我不需要做任何其他事情),我可以手动降低代码就好了。

标签: java multithreading consumer producer


【解决方案1】:

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

此外,您的生产者似乎不应该等待成功的queue.put(),而是等待应用程序前进到下一个滴答声。 myWorld.myApp.getTick() 阻塞了吗?如果没有,您的代码将无限循环,除非:

  • 还有其他线程同时修改滴答声
  • 你的线程被挂起,另一个被唤醒的线程修改了刻度

只有在可能发生变化的情况下,使用无限循环来检查条件的变化(又名轮询/旋转等待)才有意义。

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

【讨论】:

  • getTick() 线程安全吗?不,它只是在每次单独的主线程(游戏控制器)循环迭代时返回 int 变量 inc'd+1。主线程是唯一修改int 刻度的线程。每当我调试和中断时,getTickway 增加到足以满足 if 语句。生产者线程总是在那个条件语句上循环,所以我不明白为什么它最终永远看不到变化。
  • 使getTick() 返回volatile 的变量成功了。
猜你喜欢
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 2014-02-20
相关资源
最近更新 更多