Following is a rather common scenario of accessing a common resource, either in a sequential (single-threaded) or a concurrent (multi-threaded) way, for which the fastest technique is needed.
More specifically (see sample source code below), a Manager
class creates some instances of a Runnable
(or Callable
) class (Handler
) with a common resource (a Store
object). The Manager
class is actually subclassed and its execute()
method overridden to run the handlers sequentially in the same thread, or in multiple threads (e.g., via an ExecutorService
), depending on the subclass implementation.
My question is, what would be the fastest (less overhead) way of synchronizing access to the shared Store
object inside the run
(or call()
) method of each Handler
object, especially taking into account that, for single-threaded access, that synchronization is redundant (but has to be there, because there are also multi-threaded Manager
subclass implementations).
Would, for instance, a synchronized (this.store) {this.store.process()}
block be better than, say, using a Lock
object from java.util.concurrent
, before and after calling this.store.process()
? Or would a separate synchronized
method inside Handler
for each store access be faster? For example, instead of calling this.store.process()
, run something like
private synchronized void processStore()
{
this.store.process();
}
Following is the (sample) source code.
public class Manager
{
public Manager()
{
Store store = new Store(); // Resource to be shared
List<Handler> handlers = createHandlers(store, 10);
execute(handlers);
}
List<Handler> createHandlers(Store store, int count)
{
List<Handler> handlers = new ArrayList<Handler>();
for (int i=0; i<count; i++)
{
handlers.add(new Handler(store));
}
return handlers;
}
void execute(List<Handler> handlers)
{
// Run handlers, either sequentially or concurrently
}
}
public class Handler implements Runnable // or Callable
{
Store store; // Shared resource
public Handler(Store store)
{
this.store = store;
}
public void run() // Would be call(), if Callable
{
// ...
this.store.process(); // Synchronization needed
// ...
this.store.report(); // Synchronization needed
// ...
this.store.close(); // Synchronization needed
// ...
}
}
public class Store
{
void process() {}
void report() {}
void close() {}
}
In general: CAS synchronization < synchronized
< Lock
in terms of speed. Of course this will depend on the degree of contention and your operating system. I would suggest you try each and determine which is the fastest for your need.
Java also performs lock elision to avoid locking on objects that are only visible to one thread.