我有一个包含静态字段的类,其行为类似于单例:
public class A {
private static MyAPI instance = null;
protected synchronized static MyAPI getAPI() throws Exception {
if (instance == null){
// init API;
}
return instance;
}
// other methods
}
我有多个继承自A类的类,需要对API执行操作。我在多线程环境中工作,API可以一次运行一次,因此我必须确保所有子类不能同时在API上运行。为此,我在访问子类中的API时同步超类:
public class B extends A {
public void myMethod(){
synchronized (A.class) {
myAPI = getAPI();
// do stuffs with myAPI
}
}
}
使用此解决方案,我锁定整个类而不仅仅是API实例,因此当子类处理API并且性能可以降低时,我的类A的其他方法不可用。
你认为这是最好的解决方案还是你知道更好的方法?
感谢。
答案 0 :(得分:2)
我在这里考虑两个问题:
首先,因为MyAPI
对象充当单例,其他类从类A
继承的事实是无关紧要的。您也可以在非分层结构中使用其他类来引用单例。
其次,同步应该在MyAPI的代码中完成,这样您就可以以任何方式控制同步粒度。这使您也可以实现更好的封装,并且您无需担心在继续操作之前忘记获取锁定的不良行为调用者。它可以是每种方法,每种功能等。
例如:
class MyAPI {
public synchronized void doWork1() { // class level lock
...
}
public void doWork2 {
synchronized (someLockObject) {
...
}
}
public void doWork3 { // related to doWork2, lock the same object
synchronized (someLockObject) {
...
}
}
答案 1 :(得分:1)
不确定为什么您需要锁定对静态成员的每次访问权限,但请考虑使用AtomicReference and it's getAndSet() method来提高性能。
答案 2 :(得分:1)
如果您不想锁定整个类,可以锁定仅在该方法中使用的静态对象:
public class A {
private static MyAPI instance = null;
protected static Object lockForMyMethod = new Object(); //have a static lock
// other methods
}
public class B extends A {
public void myMethod(){
synchronized (A.lockForMyMethod) { //do not lock on A.class
myAPI = getAPI();
// do stuffs with myAPI
}
}
}
答案 3 :(得分:0)
我在多线程环境中工作,API可以一次运行一次,因此我必须确保所有子类不能同时在API上运行。
根据您的环境,请考虑使用ExecutorService。
例如:您可以使用固定线程池大小为1的ThreadPoolExecutor并将您的作业提交给该执行程序。
这样您就可以确保您的API仅在您提交的Callable的call()
方法中使用。
由于您只有一个线程正在工作,因此您不必担心API的并发访问。
同样,我不知道您正在使用的环境,所以使用ExecutorService可能是一个坏主意或简单无法解决问题。