可能重复:
我应该如何对线程代码进行单元测试?
经典的单元测试基本上只是将x放入并期望y out,并使该过程自动化.所以测试任何不涉及时间的东西都是有益的.但是,我遇到的大多数非常重要的错误都与时间有关.线程破坏彼此的数据,或导致死锁.不确定的行为发生了 - 一万分之一.硬的东西.
对于多线程并发系统的"单元测试"部分,有什么有用的东西吗?这些测试如何运作?是否有必要长时间运行此类测试的主题并以一种巧妙的方式改变环境,以便合理地确信它能正常工作?
我最近将我的计算机更新为更强大的计算机,配备了四核超线程处理器(i7),因此可以提供大量真正的并发性.现在我在退出()我正在开发的应用程序(使用Swing GUI)时偶尔会出现以下错误System.exit(0):
Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
at sun.java2d.Disposer.run(Disposer.java:125)
at java.lang.Thread.run(Thread.java:619)
Run Code Online (Sandbox Code Playgroud)
好吧,鉴于它开始发生在具有更多并发能力的硬件上,并且它与线程有关,并且它偶尔发生,它显然是某种时间性的东西.但问题是堆栈跟踪太短了.我只有上面的列表.它根本不包括我自己的代码,因此有点难以猜测bug的位置.
以前有没有经历过这样的事情?任何想法如何开始解决它?
编辑:因为退出Swing应用程序System.exit(0)可能是"不干净",但我不想设置主框架,EXIT_ON_CLOSE因为我想确保应用程序退出时没有任何关键的事情,我添加了一个机制,以便它执行dispose()调用之前的主框架方法System.exit(0).所以它现在应该很干净,但偶尔也会发生异常.它发生在System.exit(0)被召唤之后; dispose()工作没有问题.也就是说,它必须来自一个关闭钩子:
mainFrame.dispose(); // No problem! After this returns, all visible GUI is gone.
// In fact, if there were no other threads around, the VM could terminate here.
System.exit(0); // Throws an InterruptedException from sun.java2d.Disposer.run
Run Code Online (Sandbox Code Playgroud)
我甚至尝试Window通过循环遍历Window.getWindows()数组显式处理所有s (它包含无主Dialog …
java concurrency multithreading java-2d interrupted-exception
Goetz的Java Concurrency in Practice,第41页提到了this在构造过程中引用如何逃脱.一个"不要这样做"的例子:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
这this是通过doSomething(e)引用封闭ThisEscape实例的事实"逃避" .可以通过使用静态工厂方法(首先构造普通对象,然后注册侦听器)而不是公共构造函数(完成所有工作)来解决这种情况.这本书继续:
从构造函数中发布对象可以发布未完全构造的对象.这是真实的,即使是公布在构造函数中的最后一条语句.如果
this参考在构造期间逃逸,则认为该对象未正确构造.
我不太懂.如果发布是构造函数中的最后一个语句,那么之前没有完成所有构建工作吗?怎么会是this由当时不是有效?显然有一些伏都教在那之后继续,但是什么?
根据Swing教程:
一些Swing组件方法在API规范中标记为"线程安全"; 这些可以从任何线程安全地调用.必须从事件派发线程调用所有其他Swing组件方法.忽略此规则的程序可能在大多数情况下正常运行,但会遇到难以重现的不可预测的错误.
但是这些标记为"线程安全"的Swing组件方法是什么?实际上有吗?
是否有完整的线程安全摆动方法列表?(线程安全的Swing方法似乎很少见,所以这样的列表不能太长......)
我有一个HDF5文件,其中包含复合元素的一维(N x 1)数据集 - 实际上它是一个时间序列.首先将数据离线收集到HFD5文件中,然后进行分析.在分析过程中,大多数数据都变得无趣,只有部分数据很有趣.由于数据集可能非常大,我想摆脱不感兴趣的元素,同时保留有趣的元素.例如,保留500个元素数据集的元素0-100和200-300和350-400,转储其余数据集.但是怎么样?
有没有人有关于如何使用HDF5实现这一目标的经验?显然它可以通过几种方式完成,至少:
由于即使删除了不感兴趣的元素,文件也可能非常大,我宁愿不重写它们(这需要很长时间),但似乎需要实际释放自由空间.来自HDF5专家的任何提示?
众所周知,必须在事件派发线程上完成与Swing组件相关的任何事情.这也适用于组件背后的模型,例如TableModel.在基本情况下足够简单,但如果模型是必须在单独的线程上运行的事物的"实时视图",因为它正在快速变化,事情变得相当复杂.例如,JTable上股票市场的实时视图.股票市场通常不会发生在美国东部时间.
那么,什么是(de)耦合必须在EDT上的Swing模型的优选模式,以及必须随时随地更新的"真正的"线程安全模型?一种可能的解决方案是将模型实际拆分为两个单独的副本:"真实"模型加上其Swing对应物,这是"真实"模型的快照.然后它们会在EDT上同时(双向)同步.但这感觉就像臃肿.这真的是唯一可行的方法,还是有其他或更标准的方法?有用的图书馆 什么?
众所周知,更新Swing GUI必须仅在EDT中完成.较少的广告是从GUI 中读取内容必须/也应该在EDT中完成.例如,让我们使用ButtonModel的isSelected()方法,它告诉(例如)ToggleButton的状态("向下"或"向上").
在我看过的每个例子中,isSelected()都是从主要或任何一个线程中自由地查询.但是当我查看DefaultButtonModel的实现时,它没有同步,并且值不是volatile.因此,严格地说,isSelected()如果从任何其他线程读取它而不是从其设置的线程(当用户按下按钮时是EDT),则可以返回垃圾.还是我弄错了?
当Bloch的Effective Java中的第66项震惊时,我最初想到这个,这个例子:
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while(!stopRequested) i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
Run Code Online (Sandbox Code Playgroud)
与看起来相反,该程序永远不会终止,至少在某些机器上.stopRequested从主线程更新标志对后台线程是不可见的.可以使用同步的getter和setter或通过设置标志来修复这种情况volatile.
所以:
JGoodies Binding和JSR 295,Beans Binding有什么实际区别?它们似乎都是出于同样的目的而完成工作(采用略有不同的方法).JGoodies Binding更加成熟,但JSR 295最终将成为Java 7中JDK的一部分.
使用JDK的标准部分肯定比使用单独的库来实现相同的功能更好,但还有其他因素需要考虑吗?还有其他一些选择吗?在这些之间进行选择是相当不可逆转的架构决策......
参考我之前关于不完整构造对象的问题,我有第二个问题.正如Jon Skeet指出的那样,在构造函数的末尾有一个隐式的内存障碍,可以确保final所有线程都可以看到这些字段.但是如果构造函数调用另一个构造函数呢?在每个人的最后是否有这样的记忆障碍,或者只是在第一个被召唤的人的最后?也就是说,当"错误"解决方案是:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
正确的一个是工厂方法版本:
public class SafeListener {
private final EventListener listener;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
}
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
Run Code Online (Sandbox Code Playgroud)
以下工作是否也会起作用?
public class MyListener {
private final EventListener listener;
private …Run Code Online (Sandbox Code Playgroud) java ×8
concurrency ×3
swing ×3
binding ×1
c ×1
c++ ×1
constructor ×1
hdf5 ×1
java-2d ×1
javabeans ×1
jvm ×1
math ×1
publishing ×1
this ×1
unit-testing ×1