Java 确保一个类中只有一个线程

Java 确保一个类中只有一个线程,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个DAO类,它有多个更新DB表的方法。这些方法在整个代码库中的许多不同位置以许多不同的顺序被调用 public class Dao { public synchronized updateA() public synchronized updateB() public synchronized updateC() public synchronized getA() public synchronized getB() public synchronized get

我有一个DAO类,它有多个更新DB表的方法。这些方法在整个代码库中的许多不同位置以许多不同的顺序被调用

public class Dao {
  public synchronized updateA()
  public synchronized updateB()
  public synchronized updateC()
  public synchronized getA()
  public synchronized getB()
  public synchronized getC()
}
我遇到一个问题,Class1希望依次调用
getA()
getB()
、和
getC()
。三个表A、B和C是相关的,所以我需要在一个时间点同步它们的状态

然而,在Class1调用
getA()
之后和调用
getB()
之前,另一个线程上的Class2跳入并调用
updateB()
,这会破坏一些东西

有没有可能在有任何线程的情况下锁定整个DAO类,并且只在完成后才解锁它

我已经尝试在DAO类中放置一个静态ReentrantLock并从Class1锁定它,但我不确定如何从那里开始

我已经做到了以下几点:

public class Class1 {
  public void check() {
    dao.daoLock.lock();
    dao.getA();
    dao.getB();
    dao.getC();
    dao.daoLock.unlock();
  }
}

public class Dao {
  public static final daoLock = new ReentrantLock();
  public synchronized updateA() {
    daoLock.lock();
    // Do stuff...
  }
  public synchronized updateB() {
    daoLock.lock();
    // Do stuff...
  }
  public synchronized updateC() {
    daoLock.lock();
    // Do stuff...
  }
  public synchronized getA() {
    daoLock.lock();
    // Do stuff...
  }
  public synchronized getB() {
    daoLock.lock();
    // Do stuff...
  }
  public synchronized getC() {
    daoLock.lock();
    // Do stuff...
  }
}
我不确定解锁的位置。如果我把它放在每个DAO类方法中,它会让其他线程进入,不是吗


这里有更好的解决方案吗?

您试图在客户端同步对数据库的访问,而客户端根本不适合这样做。如果另一个客户同时写了一封信呢

最好将这种同步留给数据库本身,使用事务(,)


即使您没有多个客户机,而且永远不会,使用事务也是一个更好的解决方案。否则,即使只是执行读取操作,所有线程也会相互阻塞,这在原则上可以同时进行。

您试图在客户端同步对数据库的访问,但这从根本上说是错误的。如果另一个客户同时写了一封信呢

最好将这种同步留给数据库本身,使用事务(,)


即使您没有多个客户机,而且永远不会,使用事务也是一个更好的解决方案。否则,即使只是读取,所有线程也会相互阻塞,这在原则上可以同时发生。

除了Thomas给出的好答案外,这里还有另一个值得注意的方面:接口的编写方式应该使正确的操作变得容易;而且很难做错事

意思:如果某个操作要求您按顺序并以“整体锁定方式”调用a()、b()、c(),那么:您的接口上没有a、b、c,而是提供了一个方法abc()。。。获取锁,调用a、b、c并释放锁

因此,您应该退一步,从一个角度来看类的接口;或者更具体一点——从“单一责任原则”的角度考虑


换句话说:拥有一个提供许多完全“分离”方法的类;其中一些甚至需要“以非常特定的方式一起使用”,这是一种清晰的设计气味;因此,另一个指示是,您最好后退一步,回顾此设计。

除了托马斯给出的好答案外,还有一个值得关注的方面:接口的编写方式应该使正确的事情变得容易;而且很难做错事

意思:如果某个操作要求您按顺序并以“整体锁定方式”调用a()、b()、c(),那么:您的接口上没有a、b、c,而是提供了一个方法abc()。。。获取锁,调用a、b、c并释放锁

因此,您应该退一步,从一个角度来看类的接口;或者更具体一点——从“单一责任原则”的角度考虑


换句话说:拥有一个提供许多完全“分离”方法的类;其中一些甚至需要“以非常特定的方式一起使用”,这是一种清晰的设计气味;因此,另一个迹象表明,您最好后退一步,检查一下这个设计。

是否可以添加一个
同步更新a和B()
方法,以原子方式更新a和B?或者更改策略,以便在调用站点(可能在类实例本身上)执行同步?或者添加一个原子更新a和B的
synchronized updateA和B()?或者更改策略,以便在调用站点(可能在类实例本身上)完成同步?