如何在Java Singleton中维护可变状态

时间:2013-04-17 22:17:43

标签: java synchronization singleton osgi

我在Java中有一个Singelton(在OSGi服务中),并希望在其中维护一些状态(计数器)。

这个变量应该是静态的吗?还是同步?或两者兼而有之?

或者我应该以同步方式包装动作? (这会使var同步化吗?)

我希望服务操作的使用者增加此计数器。

public MyServiceImpl implements MyService {
    private int count = 0; // static? syncronized?

    public String helloWorld() { count++; return "Hello World"; }
    public int getHelloCount() { return count; }
}

更新:我怎么会像地图或列表那样?是否也喜欢使用这些的原子版本?或者同步更好吗?

3 个答案:

答案 0 :(得分:7)

单身人士的问题是他们需要范围。如果您在OSGi中注册服务,那么这是框架中的单例。但是,由于OSGi避免像瘟疫这样的静态,人们可以在同一个VM中启动多个框架(嵌套或兄弟),这可能意味着您的服务在不同的框架中多次注册。一般来说,这正是你想要的。如果这不够单身,那么范围应该是什么? VM,流程,机器,网络,世界?人们为你创建单身人士所提供的所有技巧都忘了告诉你他们的范围只适用于你碰巧遇到的类加载器。

在OSGi中,假设您的范围是框架。因此,只需注册一个服务并使用实例变量。由于OSGi在并发环境中运行,您必须像所有其他帖子所示,使用同步方法或更好的AtomicLong / AtomicInteger。

如果您有多个需要共享单身的服务,只需创建一个额外的服务来代表单身人士。

永远不要使用静态,因为它们可以显着降低代码的可重用性,它们具有全局变量的所有弊端。纯OSGi的优点之一是它允许你几乎完全使用实例编程,而不必使用静态和类名(遭受相同的全局变量问题)。

答案 1 :(得分:2)

这是使用Atomics的绝佳机会:

public class MyServiceImpl {
  private AtomicInteger helloCount = new AtomicInteger(0);

  public String helloWorld() {
    helloCount.incrementAndGet();
    return "Hello World";
  }

  public int getHelloCount() {
    return helloCount.get();
  }
}

这是无锁的,因此通常更快,更有效。

这种机制对单身人士或非单身人士也同样适用。

答案 2 :(得分:2)

如果您只注册一次,那么正常的OSGi服务就是该框架中的单例。如果您使用的是声明式服务,那么默认情况下会发生这种情况。

按照惯例我的意思是不是由服务工厂创建的。框架位也很重要,一些供应商在单个JVM中支持多个框架。

不要使用静态 - 这不是 OSGi方式: - )

您的担忧只是并发访问,因此正如其他人所评论的那样,AtomicLong之类的内容适合。

注意溢出 - 您希望您的计数器达到Long.MAX_VALUE(> 9,223,372,036,854,775,807)吗?否则你最终会看到负数。