我有2个线程,我想用这些线程运行Student对象的不同方法。问题是当我运行此代码时t2线程等待t1完成同步块。
为什么等待t1完成?如何使用不同的方法锁定不同的对象而不会相互阻塞?
这是主要方法;
Student student = new Student();
Thread t1 = new Thread(() -> {
try {
student.addA();
} catch (InterruptedException ex) {
Logger.getLogger(JavaApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
});
Thread t2 = new Thread(() -> {
try {
student.addB();
} catch (InterruptedException ex) {
Logger.getLogger(JavaApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
});
t1.start();
t2.start();
这是学生班;
public class Student {
private Integer a = 0;
private Integer b = 0;
public void addA() throws InterruptedException{
System.out.println("addA start");
synchronized(a){
System.out.println("addA sync start");
a++;
Thread.sleep(5000);
}
System.out.println("addA end");
}
public void addB() throws InterruptedException{
System.out.println("addB start");
synchronized(b){
System.out.println("addB sync start");
b++;
Thread.sleep(5000);
}
System.out.println("addB end");
}
}
答案 0 :(得分:5)
此:
private Integer a = 0;
private Integer b = 0;
实际上与此相同:
private Integer a = Integer.valueOf(0);
private Integer b = Integer.valueOf(0);
和the result of Integer.valueOf(0)
is cached,因此您实际上正在同一个对象上进行同步。
您可以使用new Integer(0)
获取不同的Integer
个实例。
但这只是一次又一次的问题:
a++;
实际上是:
a = Integer.valueOf(a.intValue() + 1);
所以你可能会再次遇到同样的问题,至少在a
的值超过Integer.valueOf
方法缓存的值范围之前(至少127,但依赖于实现)。< / p>
您可以应用相同的技巧:
a = new Integer(a.intValue() + 1);
然而,同步一个可变引用是一个非常糟糕的主意,因为只要执行了这一行,另一个线程就可以进入该同步块。 (不是那些已被阻止进入它的人,但之后任何线程都会到达synchronized
)。
相反,您应为每个a
和b
创建一个单独的锁定对象:
private final Object aLock = new Object();
private final Object bLock = new Object();
并相应地这些而不是a
和b
同步。