Java线程在没有通知的情况下死亡
我正在用HashMap测试并发性(出于学术目的)。我的目标是抛出一些与从多个线程修改映射结构相关的异常 结果是,负责将内容放入我的哈希映射的线程莫名其妙地死亡,而没有抛出任何类型的异常Java线程在没有通知的情况下死亡,java,multithreading,concurrency,hashmap,Java,Multithreading,Concurrency,Hashmap,我正在用HashMap测试并发性(出于学术目的)。我的目标是抛出一些与从多个线程修改映射结构相关的异常 结果是,负责将内容放入我的哈希映射的线程莫名其妙地死亡,而没有抛出任何类型的异常 public class Test { public static void main(String[] args) { Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() { public v
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());
}
}
}
公共类测试{
公共静态void main(字符串[]args){
Thread.UncaughtExceptionHandler h=新线程.UncaughtExceptionHandler(){
public void uncaughtException(线程th,可丢弃的ex){
System.out.println(“未捕获异常:+ex”);
}
};
线程a=新线程(newmytask(“a”));
线程b=新线程(newmytask(“b”));
线程c=新线程(newmytask(“c”));
线程d=新线程(newmytask(“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());
}
}
}
公共类MyTask实现Runnable{
静态AtomicInteger计数器=新的AtomicInteger(0);
静态映射映射=新的HashMap();
字符串名;
MyTask(字符串_名称){
名称=_名称;
}
@凌驾
公开募捐{
while(true){
counter.incrementAndGet();
试一试{
map.put(name+“”+counter.get(),counter.get());
}捕获(运行时异常e){
e、 printStackTrace();
}
System.out.println(name+“”+counter.get());
}
}
}
如果运行此操作,您会注意到线程将在某个点停止打印,并且贴图的大小不再改变。如果切换到ConcurrentHashMap,一切正常(它会一直打印)
请让我知道如何捕捉这样的异常/错误 我认为没有出现异常或错误。关于: 请注意,此实现未同步。如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了该映射,则必须在外部对其进行同步 您正在多个线程中修改映射,而不是同步。因此,行为是未定义的 事实上,我无法重现你描述的行为:“地图的大小不再改变”;我看到长期运行时,该值似乎没有改变;但最终它会变成一个新的值,并在那里停留一段时间
这是因为线程中的活动导致的大小更改没有立即提交到主内存。请看一看。由于您使用的是非同步的
哈希映射
,因此您将自己陷入一个活动锁中,这并不意味着线程写入没有提交到内存中。如果你看我的链接,这是两次或多次写入之间的竞争条件。即使所有字段都是易变的,这仍然可能失败。有趣!谢谢。(:男孩,那篇博文确实很长!通过从run()
中删除println()
s,我能够重现这个问题(我想这增加了我的重叠机会,因为打印需要一些时间)。这是正确的答案->并发HashMap
大小调整可以在存储桶列表中创建一个循环,使其无法迭代到某些元素。@JanezKuhar println是同步的,它间接引入了数据可见性的度量。感谢您的答案和有趣的链接!我想我只能选择一个答案。:CIt doesn不会死,它会进入无限循环,因为HashMap不是线程安全的。您不会期望它显示错误,而是消耗100%的CPU。