我无法理解为什么在以下代码中同时发生类级锁和对象级锁的异常:
似乎对象级别锁定应该在这里起作用,因为我们正在使用不同的线程来更改和访问hm(Object)值,但是仍然得到 exception(java.util.ConcurrentModificationException)。我尝试对代码中的所有三个锁定进行注释。
我知道使用 Hashtable 或 ConcurrentHashMap 可以解决此问题,但是我想知道使用HashMap缺少的概念。
< / p>
import java.util.HashMap;
class A{
StringBuilder str = new StringBuilder("ABCD");
StringBuilder exception = new StringBuilder("");
HashMap hm = new HashMap();
public void change() {
//synchronized(A.class) {
//synchronized (this){
synchronized (hm){
(this.str).append(Thread.currentThread().getName().toString());
System.out.println(Thread.currentThread().getName()+"::::::"+str);
hm.put(Thread.currentThread(), Thread.currentThread());
}
}
public void impact() {
//synchronized(A.class) {
//synchronized(this) {
synchronized(hm) {
System.out.println(Thread.currentThread()+"...Inside impact :::"+hm.get(Thread.currentThread()));
}
}
public void print() {
System.out.println("Inside print :::"+str);
System.out.println("Inside print :::exception--"+exception);
}
}
class B extends Thread{
A a;
B(A a){
this.a=a;
}
public void run() {
try {
System.out.println("Inside B run::"+a.hm);
a.change();
a.impact();
}
catch(Exception e){
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
System.out.println(sw.toString());
a.exception.append(sw.toString());
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
class C extends Thread{
A a;
C(A a){
this.a=a;
}
public void run() {
try {
System.out.println("Inside C run::"+a.hm);
a.change();
a.impact();
}
catch(Exception e){
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
System.out.println(sw.toString());
a.exception.append(sw.toString());
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
public class multiTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
for(int i=0;i<=100;i++) {
B b = new B(a);
C c = new C(a);
b.start();
c.start();
}
try {
Thread.currentThread().sleep(5000);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
a.print();
}
}
答案 0 :(得分:1)
问题出在这条线上:
System.out.println("Inside B run::"+a.hm);
这里有a.hm.toString()
的暗中隐式调用,它确实对地图项进行了暗中的迭代;但是您没有进行任何同步,因此您没有对哈希表的独占访问权。
将其放在同步块中
synchronized (a.hm) {
System.out.println("Inside B run::"+a.hm);
}
(然后使hm
成为最终的;并且不要使用原始类型)。