0

I have a class, called counter. It looks like this:

public class Counter {
  private int count;

  public Counter() {
    count = 1;
  }

  public int getCount(){
    return count;
  }

  public void incrementCount(){
    count++;
  }

I want to share a single instance of this between every user of a tomcat application. So user 1 and user 2 would both see getCount() as the same value. Assume for this that there is a technical reason why I can't store and read from a database.

Any advice?

Thanks.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Reu
  • 1,257
  • 3
  • 15
  • 30

3 Answers3

4

Just create one and store it in the application scope during server's startup.

@WebListener
public class Config implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute("counter", new Counter());
    }

    // ...
}

This way it's available in every servlet as follows:

Counter counter = (Counter) getServletContext().getAttribute("counter");
// ...

And in every JSP as follows:

<p>The count is ${counter.count}</p>

See also:


Unrelated to the concrete problem, your counter is not threadsafe. I'd suggest to use AtomicInteger instead of int.

public class Counter {
  private AtomicInteger count = new AtomicInteger();

  public Counter() {
    count.incrementAndGet();
  }

  public int getCount(){
    return count.get();
  }

  public void incrementCount(){
    count.incrementAndGet();
  }
}
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Definitely. You don't want a singleton here. – BalusC Apr 14 '11 at 20:00
  • Do I just put this into the package with the rest of the classes? – Reu Apr 14 '11 at 20:04
  • The listener? Yes truly it needs to be placed in the classpath like every other class you'd like to use in your webapp. I however assume that you're using Tomcat 7 which supports the new Servlet 3.0 annotations. Otherwise you have to get rid of `@WebListener` and declare the listener yourself in `web.xml` by ``. See also [this answer](http://stackoverflow.com/questions/4175726/how-do-i-load-a-java-class-not-a-servlet-when-the-tomcat-server-starts/4175742#4175742) for another example. – BalusC Apr 14 '11 at 20:06
2

You can use Singleton pattern.

Try this:

public class Counter {
private int count;
private static Counter instance = null;
private static Object lockObj = new Object();



private Counter() {
count = 1;
}

public static Counter Instance(){
 synchronized(lockObj){
     if(instance == null){
        instance = new Counter();
     }
 }

 return instance;
}

public int getCount(){
return count;
}

public void incrementCount(){
count++;
}
}

and somewhere in your code you can use: Counter.Instance().getCount()

Chandu
  • 81,493
  • 19
  • 133
  • 134
2

A singleton that works in Java with proper locking:

public class Counter {
  private AtomicInteger counter = new AtomicInteger(0);

  private static class Initilizer {
    private static Counter instance = new Counter();
  }

  private Counter() {}

  public Counter instance() { return Initilizer.instance; }

  public int getCount() { return counter.get() }
  public void increment() { counter.incrementAndGet(); }

}

get the count: Counter.instance().getCount()
increment: Counter.instance().increment()

The difference between the 2 answers is the synchronization and singleton initialization which is optimized for java

Asaf
  • 6,384
  • 1
  • 23
  • 44