How to maintain mutable state in a Java Singleton

拜拜、爱过 提交于 2019-12-12 14:02:40

问题


I have a Singelton in Java (in an OSGi Service) and want to maintain some state in it (a counter).

Should this variable be static? or synchronized? or both?

Or should i wrap the actions in a syncronized method? (would this be any different than just making the var syncronized?)

I want consumers of the service actions to increment this counter.

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

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

Update: How would I so something like a Map or a List? Is it preferred to use Atomic versions of these too? Or is Synchronized better for this?


回答1:


The problem with singletons is that they require a scope. If you register a service in OSGi then this is a singleton in the framework. However, since OSGi avoids statics like the plague people could start multiple frameworks (nested or as siblings) in the same VM and that could mean your service gets registered multiple times in different frameworks. In general, this is exactly what you want. If this not sufficiently singleton, then what should be the scope? The VM, the process, the machine, the network, the world? All the tricks people provide you for creating singletons forget to tell you that they scope only for the class loader you happen to be in.

In OSGi, assume your scope is the framework. So just register a single service and use instance variables. Since OSGi runs in a concurrent environment, you must, as all the other posts indicate, use synchronized methods or better AtomicLong/AtomicInteger.

If you have multiple services that need to share a singleton, just create an extra service to represent the singleton.

Never use statics since they can reduce the reusability of your code significantly, they have all the evils of global variables. One of the beauties of pure OSGi is that it allows you program almost completely with instances and never have to work with statics and class names (which suffer from the same global variable problem).




回答2:


This is a perfect opportunity for using Atomics:

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

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

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

This is lock-free and therefore generally faster and more efficient.

This mechanism will work just as well with singletons or non-singletons.




回答3:


A normal OSGi service is a singleton in that framework if you register it only once. And if you're using Declarative Services that is what will happen by default.

By normal I mean not created by a service factory. Also the framework bit is important, some vendors support multiple frameworks in a single JVM.

Do not use static - this not the OSGi way :-)

Your concern is only concurrent access, so as others have commented, something like AtomicLong would be suitable.

Watch out for overflow - do you expect your counter to reach Long.MAX_VALUE (> 9,223,372,036,854,775,807)? Otherwise you'll eventually see negative counts.



来源:https://stackoverflow.com/questions/16071209/how-to-maintain-mutable-state-in-a-java-singleton

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!