如何用不同的方法锁定不同的对象?

时间:2017-10-24 13:13:34

标签: java multithreading

我有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");
  }

}

1 个答案:

答案 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)。

相反,您应为每个ab创建一个单独的锁定对象:

private final Object aLock = new Object();
private final Object bLock = new Object();

并相应地这些而不是ab同步。