2

Given what I understand of concurrency in java, it seems shared access to instance members must be coded to handle multi-threaded access only if the threads access the same instance of a given object, such as a servlet.See here: Why instance variable in Servlet is not thread-safe

Since not all applications are servlet based, how do u determine which objects need to accomodate multi-threaded access? For example, in a large, non-servlet based enterprise application, given the sheer number of classes, how do you determine from a design stand-point which objects will have only one instance shared across multiple threads during run-time? The only situation I can think of is a singleton.

In Java's EL API, javax.el.BeanELResolver has a private inner class that uses synchronization to serialize access to one of its members. Unless I am missing something, BeanELResolver does not look like a singleton, and so each thread should have its own instance of BeanELResolver. What could have been the design consideration behind synchronizing one of its members?

Community
  • 1
  • 1
sotn
  • 1,833
  • 5
  • 35
  • 65
  • Synchronization is a safety measure. You should use it in a multi-threaded environment if the *reference* of an instance escapes. – TheLostMind Jan 13 '15 at 14:46
  • 2
    You should know before you write the class if instance will be used concurrently. It's an app design choice that the coder must allow for in he impl. – Bohemian Jan 13 '15 at 15:00
  • This is a complex subject - the best advice is to read Java Concurrency in Practice by Brian Goetz - all you need to know is in there. – BarrySW19 Jan 13 '15 at 15:10

3 Answers3

1

There are many cases in which the state of one class can be shared across many threads, not just singletons. For example you could have a class or method creating objects (some sort of factory) and injecting the same dependency in all the created objects. The injected dependency will be shared across all the threads that call the factory method. The dependency could be anything: a counter, database access class, etc.

For example:

class ThreadSafeCounter{
  /* constructor omitted */
  private final String name;
  private final AtomicInteger i = new AtomicInteger();
  int increment() { return i.incrementAndGet(); }
}

class SheepTracker {
  public SheepTracker(ThreadSafeCounter c) { sheepCounter = c;}
  private final ThreadSafeCounter sheepCounter;
  public int addSheep() { return c.increment(); }
}

class SheepTrackerFactory {
  private final ThreadSafeCounter c;
  public SheepTracker newSheepAdder() {
    return new SheepTracker(c);
  }
}

In the above, the SheepTrackerFactory can be used by many threads that all need to do the same thing, i.e., keeping track of sheep. The number of sheep across all the threads is maintained in a global state variable, the ThreadSafeCounter (it could be just an AtomicInteger in this example, but bear with me, you can imagine how this class could contain additional state/operations). Now each SheepTracker can be a lightweight class that performs other operations that don't require synchronization, but when they need to increment the number of sheep, they will do it in a thread-safe way.

Giovanni Botta
  • 9,626
  • 5
  • 51
  • 94
0

Any instance can be shared between threads, not only singletons.

That's why it's pretty hard to come up with a design where anyone in a development team can instantly see which types or instances will be shared between threads and which won't. It outright impossible to prevent sharing of some instances. So the solution must be somewhere else. Read up on "memory barriers" to understand the details.

Synchronization is used for two purposes:

  1. Define memory barriers (i.e. when changes should become visible to other threads)
  2. Make sure that complex data structures can be shared between threads (i.e. locking).

Since there is no way to prevent people from sharing a single BeanELResolver instance between different threads, they probably need to make sure that concurrent access doesn't break some complex structure (probably a Map).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • No `String` can ever be a _singleton_. A singleton, by definition, is the only instance of its class. There are thousands of distinct instances of `String` in even the most trivial Java program. (E.g., every class name, field name, and method name is a String.) – Solomon Slow Jan 13 '15 at 16:06
  • @jameslarge: I mentioned `String` because some people confuse immutable or value types with singletons. Usually even `public final static String` constants aren't singletons (`javac` creates a copy if you reference it from an outside class, for example in annotations). – Aaron Digulla Jan 14 '15 at 08:11
  • I think we are not in agreement about what "singleton" means. I'd go with the "Design Patterns" definition if I had a handy copy, but I'm pretty sure the Wikipedia definition is equivalent: http://en.wikipedia.org/wiki/Singleton_pattern By that definition, it doesn't make sense to say "Usually...": No Java `String` can _ever_ be a singleton. – Solomon Slow Jan 14 '15 at 15:02
  • @jameslarge: You can create a single instance of a String like any other object and pass that around like any other singleton. For example in Spring: `@Bean String public foo() { return "foo"; }` would create a singleton. – Aaron Digulla Jan 14 '15 at 15:29
  • The method, foo(), in your example does not create a singleton: It returns a string literal. It returns the _same_ string every time it is called, but that is not what "singleton" means. The @Bean annotation will cause the Spring framework to call foo() at some point, and Spring will incorporate the string literal into a new _bean_. I don't know whether the bean is a singleton or not because I don't know Spring, but the string itself is not a singleton. It can't be a singleton because it is not the only instance of its class. – Solomon Slow Jan 14 '15 at 15:52
  • @jameslarge: Ah, in my code base, we have singletons that aren't locked by type. I updated my answer. – Aaron Digulla Jan 14 '15 at 17:10
0

You're asking a very broad question, so I'll try to answer with a broad answer. One of the first things your design has to consider, long before you dive into classes, is the design of the application's threading. In this step you consider the task at hand, and how to best utilize the hardware that has to solve it. Based on that, you choose the best threading design for your application.

For instance - Does the application perform intense computations? If so, can parts of the computation be parallelized to make better use of a multi core CPU? If so, make sure to design multiple threads compute on different cores in parallel.

Does your application perform a lot of I/O operations? If so, it's better to parallelize them so multiple threads could handle the input/output (which is slow and requires a lot of waiting for external devices) while other threads continue working on their own tasks. This is why servlets are executed by multiple threads in parallel.

Once you decide one the tasks you want to parallelize and the ones you prefer executing in a single thread, you go into the design of the classes themselves. Now it's clear which parts of your software have to be thread safe, and which don't. You have a data structure that's being accessed by a thread pool responsible for I/O? It has to be thread safe. You have an object that's being accessed by a single thread that performs maintenance tasks? It doesn't have to be.

Anyway, this has nothing to do with singletons. Singlton is a design pattern that means that only a single instance of a certain object can be created. It doesn't say anything about the number of threads accessing it or its members.

Malt
  • 28,965
  • 9
  • 65
  • 105