- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
因此,首先,我绝对知道Swing的主要线程安全规则:所有GUI组件交互都必须在事件分发线程上进行。但是,由于我一直在编写代码并按照Model-View-Controller准则进行工作,所以我一直想找到一种方法来解决Swing组件数据模型。
警告,这是一篇很长的文章,但是我想真正地解释一下我的思考过程。我在这里很有创造力,主要是想获得反馈,以了解这是否切实可行。
我现在正在使用的程序现在使用一个 Controller 类,该类实现了ActionListener来监听UI类中组件的事件。调用actionPerformed()方法时,它将通过执行程序将ActionEvent传递到另一个线程,该执行程序在该事件执行程序中解析事件并更新我的程序的模型。这些模型触发PropertyChangeEvent,这些事件包装在SwingUtilities.invokeLater中,因此它们对GUI所做的更改将在EDT上进行。
到目前为止,一切似乎都是100%的犹太洁食。
但是然后我有了这个JList。我要做的是从EDT修改其组件,然后对其进行更新。我已经提出了几个想法,实际上我正在探索实现这一目标的多种途径。特殊的添加/删除PropertyChangeEvents或传递新列表以用每个事件替换现有列表只是我的一些想法。
但是我在这篇文章中提出了我最疯狂的想法:一个线程安全的ConcurrentListModel,可以通过任意数量的线程进行修改,但仍然符合Swing的线程安全规则。
所以,让我解释一下:
对于ListModel,它仅通过三种方式与JList本身进行交互。这些方式中的每一种都为并发访问提出了一个独特的问题:
1)从基础集合(getElement,getSize)中检索信息。 JList需要能够访问基础集合以在其 View 中正确显示其值。此基础集合上的任何同步都可能导致UI的响应性问题,但是如果此集合被多个线程修改,则结果将是任何数量的线程一致性问题。
2)添加/删除ListDataListeners。当然,要添加的监听器是BasicListUI.ListDataHandler,它链接到JList本身。 AbstractListModel实现允许将任意数量的ListDataListeners添加到EventListenerList中。同样,由于响应问题,此列表在EDT需要访问时无法同步,但是如果由多个线程对其进行了修改,则无法保证此列表状态的一致性。
3)触发ListDataEvents。 JList没有链接到模型中的基础集合,只有模型本身。因此,每当模型对基础集合进行更改时,它都必须将ListDataEvent激发到JList。然后,JList调用我前面提到的getElement/size方法。这些事件必须在EDT上触发。
因此,乍一看,这是一个与JList的关系使其无法从EDT进行修改的组件。除了...我是一个固执的SOB,我想我已经找到了解决方法。我将要描述的所有内容,请在做出判断时以任何明显的错误回应。
我列出的三件事,它们不要求ListModel仅由EDT触及,它们仅要求其中的某些部分仅由EDT触及。具体来说,它要求此类的STATE FIELDS(基础列表和EventListenerList)在EDT上保持线程局部。该类的所有方法都以一种或另一种方式与这两个字段进行交互。只要这些方法最终对这些字段产生的影响仅在EventDispatchThread上执行,则调用它们的线程无关紧要。
此外,由于仅在单个线程上修改了类的状态,所以根本不需要任何同步,因为状态字段保持为线程局部的。这样可以避免因Swing组件等待锁定而导致的潜在响应错误。
那么,这一切最终意味着什么?我将展示我的示例代码,以便您可以真正了解我的意思。这是按照我的设计的一个简单的add()方法(注意:我还希望最终产品遵循Collections API和List接口(interface),因此要使用方法签名):
public boolean add(final E element){
final boolean result = false;
if(SwingUtilities.isEventDispatchThread()){
result = swingAdd(element);
}
else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
result = swingAdd(element);
}
});
}
return result;
}
private boolean swingAdd(E element){
int index = list.size(); //The current size will be size - 1 after the add, aka the index of the element being added.
boolean result = list.add(element);
fireContentsChanged(this, index, index);
return result;
}
最佳答案
因为这是easy to get wrong,所以建议您使用 java.util.concurrent
提供的现有功能。
对于 JList
的特殊情况,请使用SwingWorker
的实现 Future
来更新ListModel
的实现中的process()
,这将在事件分发线程上调用。使用SwingWorker
的适当实现作为FIFO缓冲区来构造BlockingQueue
。然后,在实现take()
时publish()
和doInBackground()
新到达的元素。请注意,take()
阻止doInBackground()
是可以的;用户不会注意到。现在,您程序中的任何其他线程都可以add()
,offer()
或put()
队列中的元素,并完全确保该元素以最小的等待时间出现在JList
中。
对于您的BlockingQueue
,请考虑为元素的固定大小的缓冲区提供一个ArrayBlockingQueue
。考虑元素的有限大小缓冲区的LinkedBlockingDeque
。如果其他线程可以阻塞,请使用put()
;否则,请使用offer()
。需要检查时使用add()
;并在需要捕获IllegalStateException
的情况下使用ojit_code。
关于java - Java:ConcurrentListModel-试图绕过Swing线程安全规则,我是否陷入困境或发疯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32039719/
我是 JavaFx 新手,正在尝试编写我的刽子手游戏。我现在必须检查保存我的词典的文件是否在那里。如果没有,请用户输入其位置。我试图在弹出窗口中执行此操作,要求用户输入位置并点击按钮,该按钮反过来将导
我卡住了。我试图用 SQLite 表的字段填充 ListView 。我对 Android 编程很陌生。关于我为什么会收到此错误的任何建议: 10-24 10:24:31.154: ERROR/Andr
我正在编写一个 java 程序,它接受用户输入的数字 x,对从 1 到 x(包括 x)的所有可被 3 整除的数字求和,并显示总和。它编译没有错误但是当我执行程序时,它陷入循环并继续执行直到我关闭命令提
JS 和 Web 编程新手。 我有一个图像在 Canvas 上沿水平轴移动。当图像到达某个点时,我希望它停止、缩放然后旋转。我使用的方法会导致无限循环,我不明白为什么。 这是被调用的方法 while
我制作了一个使用表单、php 和 javascript 进行登录和注销的页面。 但唯一的问题是,当您提交表单并且数据发生更改时,直到页面重新加载后才会更新。 注意lo
我在查询时陷入困境。我想根据“时间和点赞数”查询帖子,但不知道如何在 firebase 上查询。示例: Query mquery =FireBaseDatabase() getReference().
这个问题已经有答案了: Why does my ArrayList contain N copies of the last item added to the list? (5 个回答) 已关闭 6
所以,我有一个项目,任务是这样表述的: 您需要创建一个名为 Candidate 的类,它存储参加选举的人的姓氏以及他们获得的票数。您还应该有访问每个字段的方法。此时,这些字段不需要修改器,因为它们不应
我正在解决 Java 编程类(class)中的作业问题,但我陷入了困境。我会预先告诉你,我绝不是专家,并且对 Java 或一般编程了解不多。 我遇到的问题实际上不是我的作业问题,而是书中的一个例子,我
我正在用java编写一个客户端程序。服务器是用C++编写的。当我从以下位置发送消息时客户端到服务器就可以了。但是在接收过程中我的客户端线程陷入了这个调用 in = new BufferedReader
我正在参加 Edx 上的在线类(class) cs50,我有一个作业,其中我必须创建一个程序,用户在其中输入关键字(然后用于加密)和需要在 Vigenere 中加密的字符串。密码。 Vigenere
我遇到了陷入 getIntLimited 函数的问题。在调整数量中,我需要它检查用户是否输入了正确的数字,而不是多于或少于所需的数字,而不是字母。我没有对“库存”选项这样做,只在“检查”选项中这样做。
我更喜欢创建一个 Dictionary 对象并向其中添加 3 个单词。我的程序没有编译错误,但在第二个 for 循环中出现运行时错误,问题出在 addNewWord 函数中吗?我需要传递一个指向 Di
该程序的要点是获取 2 个文件,一个是字典,另一个是文本,创建一个输出文件,并将文本文件中的所有单词放入其中,但将文本文件中不存在的单词大写字典。 当我运行程序时,它不断要求输入,所以看起来我陷入了
我正在为我的 C++ 类(class)做作业。在这个作业中,我需要编写一个程序,从 cin 中读取数字,然后对它们求和,当使用 while 循环输入 0 时停止。 我已经编写了代码并获得了我需要的结果
这是我到目前为止所得到的- $awards_sql_1 = mysql_query('SELECT * FROM categories WHERE section_id = 1') or die(my
我想弄清楚某个步骤何时发生。所以我编写了一个名为 countSteps 的方法来执行此操作。它的问题是我陷入其中,因为在 while 循环中我不断获取新数据,而且我认为它永远不会返回到 onSenso
我有点卡在一个问题上了。我有一个 Spring + Hibernate 应用程序,最近几天表现得很奇怪。 通常,即使在 Debug模式下,它也会引导大约 15 秒。 几天后,在没有显示任何重大错误或问
我是编程新手,我想知道是否有人可以帮助我解决这个问题?它似乎处于连续循环中,我一直在更改它并尝试不同的方法近一个小时,将不胜感激。 #include "stdafx.h" #include
我正在用 Python 创建一个聊天服务器,并且对这门语言的了解还很浅。我现在有 1 个问题,我想在进一步解决之前解决,但我似乎找不到解决问题的方法。 这是一个持续的 while 循环.. 下面的代码
我是一名优秀的程序员,十分优秀!