Java JTable中的并发问题
我有一个问题,我有一个JTable和一个自定义模型,在渲染阶段修改模型时会出现并发访问问题。我收到一个如下所示的异常,因为我假设它获得了表的长度,模型被更新,然后它访问一个不存在的模型元素。AbstractTableModel需要在呈现期间使用行/列索引重新访问模型以获取所需信息,并且似乎没有任何锁定,这意味着数据可以自由更改Java JTable中的并发问题,java,swing,concurrency,locking,jtable,Java,Swing,Concurrency,Locking,Jtable,我有一个问题,我有一个JTable和一个自定义模型,在渲染阶段修改模型时会出现并发访问问题。我收到一个如下所示的异常,因为我假设它获得了表的长度,模型被更新,然后它访问一个不存在的模型元素。AbstractTableModel需要在呈现期间使用行/列索引重新访问模型以获取所需信息,并且似乎没有任何锁定,这意味着数据可以自由更改 Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 2,
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.LinkedList.checkElementIndex(LinkedList.java:553)
at java.util.LinkedList.get(LinkedList.java:474)
at koku.ui.PlayerList$PlayerInfoTblModel.getValueAt(PlayerList.java:250)
at javax.swing.JTable.getValueAt(JTable.java:2720)
at javax.swing.JTable.prepareRenderer(JTable.java:5718)
at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2117)
at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2019)
at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1815)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:778)
at javax.swing.JComponent.paint(JComponent.java:1054)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paint(JComponent.java:1063)
at javax.swing.JViewport.paint(JViewport.java:725)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paint(JComponent.java:1063)
at javax.swing.JComponent.paintChildren(JComponent.java:887)
at javax.swing.JComponent.paint(JComponent.java:1063)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5206)
at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295)
at javax.swing.RepaintManager.paint(RepaintManager.java:1217)
at javax.swing.JComponent._paintImmediately(JComponent.java:5154)
at javax.swing.JComponent.paintImmediately(JComponent.java:4964)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:781)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:739)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:688)
at javax.swing.RepaintManager.access$700(RepaintManager.java:59)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1632)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:660)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
想知道解决这个问题的最好方法是什么
干杯,Chris如果要进行并发访问,则需要同步模型。 尝试阅读教程 祝你好运
PS:有时候你可以为你的软件想出另一种解决方案,而不是并发访问。此外,为了获得更好的答案,您可以发布一些应用程序代码。Swing组件/模型应该始终从AWT线程更新,而不能从其他线程更新
请参阅,对于长时间运行的任务我建议对所有TableModel访问使用釉面列表: 我已经在很多项目中使用了它们来处理一些相当繁重的数据,而且它工作得非常完美。它将表格模型抽象为一个ArrayList,您可以将其封装在同步的表格列表和过滤器列表中,这样您就可以轻松安全地完成各种真正复杂的工作 您还可以添加监听器,并在修改TableModel时得到通知这是我的方法:
- 有一个从后台线程更新的数据模型。您不能直接从Swing使用此模型
- 数据模型通过事件通知其侦听器。这些事件包含所需的所有内容—任何侦听器都不应该调用数据模型来检索某些值。(旁注:对于非GUI目的,您最终可能希望对数据模型进行直接调用,但对于Swing,您肯定不希望这样做。无论采用哪种方式,都没有必要-事件包含所有内容)这些侦听器中的一个将依次更新表模型,但在事件调度线程上,仅使用事件中的信息
- 然后是表模型,它为JTable提供了各种getter(getValueAt、getColumnCount等)。表模型infact保存数据模型的本地缓存副本,该副本仅通过传入事件更新,传入事件在EDT上处理,因为侦听器在EDT上运行。因此,不直接调用底层数据模型是非常重要的,因为这是从其他线程更新的——当JTable需要为第X行的某个单元格指定值时,这一行可能不再存在。获取实际数据的唯一方法是轮询本地缓存。因此,数据模型的本地副本也在EDT上进行操作。这一点很重要,因为在操作本地副本之后,您通常会调用一些fireTableXxx()方法,以便让所有视图更新自己。由于视图也将在EDT上更新自身,因此无法在此时间窗口中操作表模型:在表刷新完成后,将有效地执行任何invokeLater(…)
- 视图JTable调用EDT上TableModel上的getter李>
- 注册侦听器后,它将接收所有必要的事件,以便与数据模型同步
- 将实际的EDT模型与JTable分开,并通过将调用委托给EDT模型来实现TableModel。这样,您可以在单个EDT模型上使用无限的Swing侦听器。这很好,因为Swing模型(TableModel、ListModel、ComboBoxModel等)的实现是非常小的、简单易懂的实现,并且满足了DRY原则——不要重复自己的工作。EDT模型代码是集中的,并且可以重用。Swing模型成为适配器,不存储状态
- 每个Swing模型都以某种方式注册在EDT模型上李>
- EDT模型通知每个注册的Swing模型。例如,AbstractTableModel实现将通过调用
通知正在侦听的JTable来响应此类通知fireTableXxxChanged()
- Swing模型顶部的视图(例如JTable)
- EDT模型之上的Swing模型(例如AbstractTableModel)
- 侦听器,监听EDT模型,通过发送更高级别的事件(例如
)对EDT模型事件作出反应tableModel.fireTableXxxChanged()
- EDT模型位于并发模型之上。该模型实际上是一个助手模型,而不是“业务逻辑状态”引用。它实际上是底层实际模型的快照,在Swing组件的更新过程中提供了一致、不变的状态。因此,EDT模型是GUI层中的助手模型
- 侦听器,侦听并发模型,在事件调度线程上更新EDT模型。此侦听器可以将多个并发到达的事件捆绑在一个事件中以提高效率
- 并发模型根本不关心任何与Swing/EDT相关的东西。此模型是纯业务逻辑