Java:在断点调试期间检测隐式队列中的“gridlock”

时间:2011-01-04 15:25:13

标签: java multithreading debugging queue

我有一个Java应用程序,它处理来自通过串行端口到达的数据的数据流,并在Swing UI中显示摘要。

它工作正常,但是当我在某些线程(例如Swing事件调度线程)中在Eclipse中设置断点时,我在JVM爬行停止之前有一段有限的时间:传入的数据仍在处理中,并且某个系统队列,无论是数据队列还是事件队列,都会过满。

有什么方法可以在上游线程中检测到这一点,以便我的上游处理在调试期间开始丢弃数据?

如果我的程序显式使用队列,我可以在队列大小过高时丢弃数据。

但如果队列是“隐含的”,我不能这样做,例如它由我直接控制之外的其他软件管理。我可以想到两种可能性:

  1. 如果我正在使用SwingUtilities.invokeLater()或其他调用SwingUtilities.invokeLater()的UI框架,如何检测Dispatch线程是否使用事件进行备份?

  2. 如果我正在使用ExecutorService.submit(),如何检测执行程序的任务队列是否已备份?


  3. 更新:我想我已经通过包装我的ExecutorService解决了#2:

    AbstractPipelineExecutor.java:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Future;
    import java.util.concurrent.RejectedExecutionException;
    
    /**
     * pipeline executor
     */
    abstract public class AbstractPipelineExecutor {
        /**
         * a pipeline scheduled item
         */
        public interface Task extends Runnable
        {
            /**
             * if item cannot be run, this is called instead
             */
            public void denied();
        }
    
        final private ExecutorService executor;
    
        public AbstractPipelineExecutor(ExecutorService executor)
        {
            this.executor = executor;
        }
    
        /**
         * submit an item to be executed
         * @param task pipeline item
         */
        public Future<?> submit(final Task task)
        {
            Future<?> result = null;
            if (this.executor.isShutdown())
            {
                task.denied();
            }
            else
            {
                try
                {
                    onSubmit(task);
                    result = this.executor.submit(new Runnable() {
                        @Override public void run()
                        {
                            onBeginExecute(task);
                            try
                            {
                                task.run();
                            }
                            catch (RuntimeException e)
                            {
                                onExecutionException(task, e);
                            }
                            finally
                            {
                                onEndExecute(task);
                            }
                        }
                    });
                }
                catch (RejectedExecutionException e)
                {
                    task.denied();
                }
            }
            return result;
        }
    
    
        /**
         * event handler: item is submitted
         * @param task pipeline item 
         */
        abstract protected void onSubmit(Task task) throws RejectedExecutionException;
        /**
         * event handler: item execution is begun
         * @param task pipeline item 
         */
        protected void onBeginExecute(Task task) {}
        /**
         * event handler: item throws a runtime exception
         * @param task pipeline item 
         */
        protected void onExecutionException(Task task, RuntimeException e) {
            throw(e);
        }
        /**
         * event handler: item execution is ended
         * @param task pipeline item 
         */
        protected void onEndExecute(Task task) {}
    }
    

    BoundedPipelineExecutor.java:

    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.RejectedExecutionException;
    
    public class BoundedPipelineExecutor extends AbstractPipelineExecutor {
    
        public BoundedPipelineExecutor(ExecutorService executor, int bound) {
            super(executor);
            this.q = new ArrayBlockingQueue<Task>(bound);
        }
    
        final private ArrayBlockingQueue<Task> q; 
    
        @Override public void onSubmit(Task task)
        {
            if (!this.q.offer(task))
                throw new RejectedExecutionException(task.toString());
        }
        @Override public void onBeginExecute(Task task)
        {
            this.q.remove();
        }
    }
    

1 个答案:

答案 0 :(得分:1)

我建议他们不要直接从您的IO类中使用SwingUtilities.invokeLater,而是应该更新一个“摘要”,以便在更新UI时做出明智的决定。即使没有调试断点,您也不希望繁重的IO操作泛滥用户界面。

因此,创建一个接收和处理数据的类,并允许您的用户界面以适当的间隔轮询该信息。