如何在超类的静态字段上同步访问?

时间:2012-01-17 10:17:14

标签: java static synchronization

我有一个包含静态字段的类,其行为类似于单例:

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的其他方法不可用。

你认为这是最好的解决方案还是你知道更好的方法?

感谢。

4 个答案:

答案 0 :(得分:2)

我在这里考虑两个问题:

  1. 首先,因为MyAPI对象充当单例,其他类从类A继承的事实是无关紧要的。您也可以在非分层结构中使用其他类来引用单例。

  2. 其次,同步应该在MyAPI的代码中完成,这样您就可以以任何方式控制同步粒度。这使您也可以实现更好的封装,并且您无需担心在继续操作之前忘记获取锁定的不良行为调用者。它可以是每种方法,每种功能等。

  3. 例如:

    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可能是一个坏主意或简单无法解决问题。