我正在使用HashMap测试并发性(出于学术目的)。我的目标是抛出一些与从多个线程修改地图结构相关的异常。
最终,有任务将东西放入我的哈希映射中的线程莫名其妙地死掉而没有抛出任何异常......
public class Test {
public static void main(String[] args) {
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread th, Throwable ex) {
System.out.println("Uncaught exception: " + ex);
}
};
Thread a = new Thread(new MyTask("A"));
Thread b = new Thread(new MyTask("B"));
Thread c = new Thread(new MyTask("C"));
Thread d = new Thread(new MyTask("D"));
a.setUncaughtExceptionHandler(h);
b.setUncaughtExceptionHandler(h);
c.setUncaughtExceptionHandler(h);
d.setUncaughtExceptionHandler(h);
a.start();
b.start();
c.start();
d.start();
while (true) {
System.out.println(MyTask.map.size());
}
}
}
public class MyTask implements Runnable {
static AtomicInteger counter = new AtomicInteger(0);
static Map<String, Integer> map = new HashMap<>();
String name;
MyTask(String _name) {
name = _name;
}
@Override
public void run() {
while (true) {
counter.incrementAndGet();
try {
map.put(name + "_" + counter.get(), counter.get());
} catch (RuntimeException e) {
e.printStackTrace();
}
System.out.println(name + "_" + counter.get());
}
}
}
如果你运行它,你会发现线程会在某个时刻停止打印,并且地图的大小不再改变。如果切换到ConcurrentHashMap,一切正常(它会一直打印)。
请告诉我如何捕获此类异常/错误!
答案 0 :(得分:4)
我认为没有发生异常或错误。参考Javadoc of HashMap
:
请注意,此实施未同步。如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。
您正在多个线程中修改地图,而不是同步。因此,行为未定义。
实际上,我无法重现你所描述的行为:“地图的大小不再变化”;我看到长跑,价值似乎没有变化;但最终它变成了一个新值,它会停留一段时间。
原因是由于线程中的活动导致的大小变化没有立即提交给主内存。
答案 1 :(得分:3)
看看http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html。由于您使用的是非同步的HashMap
,因此您将进入实时锁定状态。