2016-08-23 57 views
0

我有一个DAO类,它有更新数据库表的多个方法。这些方法在代码库中的许多不同位置以许多不同的顺序调用。确保只有一个线程在一个类

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类的方法中,它会让其他线程进入吗?

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

+0

也许增加一个'synchronized updateAandB()'方法来自动更新A和B?或更改您的策略,以便在呼叫站点完成同步(可能在类实例本身)? – assylias

回答

3

您试图在客户端同步对数据库的访问,这基本上是错误的地方。如果另一位客户在此期间进行了写作会怎么样?

使用交易MySQL,PostgreSQL)将这种同步留给数据库本身更好。

即使您没有多个客户端,也永远不会,使用事务是一个更好的解决方案。否则,即使他们只是在执行读操作,所有的线程都会被阻塞,原则上这可能会同时发生。

1

除了托马斯的好回答,还​​有一个方面值得一看:接口应该用一种方式写出来,这样可以很容易地做正确的事情;并且很难做错事。

含义:如果某些操作需要按顺序调用(),b(),c(),并且采用“总体锁定方式”,则:而不是在界面上使用a,b,c,你提供了正确的一个方法abc()...获取锁,调用a,b,c并释放锁。

所以,你应该退一步,从SOLID的角度看看你的班级界面;或更具体的 - 从事物的“单一责任原则”方面考虑。

换句话说:有一个类提供了很多完全“不连贯”的方法;其中一些甚至需要“以非常特定的方式一起使用”,这是一种清晰的设计气味;所以另一个迹象表明你最好退后一步并回顾一下这个设计。

相关问题