我有 2 个线程,我想用这些线程运行 Student 对象的不同方法。问题是当我运行此代码时,t2 线程等待 t1 完成同步块(synchronized block)。
为什么要等待 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();
这是学生类(class);
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");
}
}
最佳答案
这个:
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,但取决于实现)。
您可以应用相同的技巧:
a = new Integer(a.intValue() + 1);
但是,在可变引用上进行同步是一个非常糟糕的主意,因为一旦执行了该行,另一个线程就可以进入该同步块(synchronized block)。 (不是那些已经被阻止进入的线程,而是任何随后到达同步
的线程)。
相反,您应该为每个 a
和 b
创建一个单独的锁定对象:
private final Object aLock = new Object();
private final Object bLock = new Object();
并同步这些,而不是相应的a
和b
。
关于java - 如何用不同的方法锁定不同的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46911543/