Reputation: 13
I am working on the following piece of code. Two threads requiring their own instance of a singleton. Thread Local is an obvious solution to this. However I am still facing issues running the threads with their own local copy. I have an example of the scenario in a couple of java classes.
public class Singleton1 {
private int i = 0;
private static Singleton1 instance;
private Singleton1() {
}
public static final Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
public int increment() {
return i++;
}
}
public class Holder1 {
private final Singleton1 instance;
public Holder1() {
ThreadLocalSingleton1 singleton1 = new ThreadLocalSingleton1();
instance = singleton1.get();
}
public int increment() {
return instance.increment();
}
private class ThreadLocalSingleton1 extends ThreadLocal<Singleton1> {
@Override
protected Singleton1 initialValue() {
return Singleton1.getInstance();
}
}
}
public class HolderTest {
/**
* @param args
*/
public static void main(String[] args) {
HolderTest test = new HolderTest();
HolderThread thread1 = test.getHolderThread("thread1");
HolderThread thread2 = test.getHolderThread("thread2");
thread1.run();
thread2.run();
}
public HolderThread getHolderThread(String name) {
return new HolderThread(name);
}
private class HolderThread implements Runnable {
String name;
Holder1 holder1 = new Holder1();
public HolderThread(String name) {
this.name = name;
}
@Override
public void run() {
while (true) {
System.out.println(name + " " + holder1.increment());
}
}
}
When the ThreadLocal wrappers call getInstance on the Singleton classes I do not get a new instance each time? How do I make this work for my purposes?
The code above is a simple version of the actual code I am working with. I have Singleton classes which I cannot change from being singletons. I am creating a test client which needs to run as a single process but with many threads. Each of these threads needs to have its own instance of these singletons.
Upvotes: 1
Views: 5826
Reputation: 718826
You seem to be painted into a corner.
On the one hand, you have an existing codebase that you need to test and that code uses (genuine, properly implemented) singleton objects. In particular, the declaration of the Singleton1()
constructor as private
in your examplar class Singleton1
makes it impossible to declare a subclass.
On the other hand, your testing requires you to write a client with lots of these Singleton1
instances.
On the face of it, that is impossible. There is no way to make two instances of the Singleton1
class in the JVM, and there is no way to declare a (compilable / loadable) subclass of Singleton1
.
This is per design; i.e. it is what the designer of the Singleton1
class intended. (And if not, then the answer is to change Singleton1
to make it easier to test. For example, by making the Singleton1
constructor not private
so that multiple instances can be created for test purposes. )
(For instance, your current attempt at implementing ThreadLocalSingleton1
fails because the Singleton1.getInstance()
returns the global instance of Singleton1
. No matter what you do, there is no way to create any other instance of the Singleton1
class.)
However, I can think of two workarounds for your particular use-case.
I am writing a test client which needs to run as as single java process. The test client is used for load testing will have X threads accessing a server using a core project (that I cannot change too much) which has many singletons. The singletons hold state which will be required per thread.
Here are the workarounds:
Instead of running one JVM with N instances of your test thread, run N separate JVMs each with a single test thread. Each JVM / test thread can have its own instance of Singleton
.
Have each of your test threads create a new classloader, and use that classloader to dynamic load the Singleton1
class and everything with a direct or indirect static dependency on the Singleton1
type. The idea is for each classloader to load its own copy of the Singleton1
class. Since each copy will be a distinct type1, it will have its own private static Singleton1 instance
variable.
Note that these workarounds do provide not "thread-local" instances of your Singleton1
class. That is both technically impossible ... and a contradiction of the definition of singleton.
In both cases you have true singleton instances, but they are instances of different Singleton1
types ... for different reasons.
1 - At runtime, the type of a class instance is conceptually a pair consisting of the fully qualified name of the class and the identity of the classloader that loaded the class. If the same bytecode file is loaded by different classloaders, then you get different runtime types.
Upvotes: 1
Reputation: 21
Please, take a look at the ThreadLocal
working example below:
public class YourDataHolder {
private static ThreadLocal dataVariable = new ThreadLocal();
private static YourDataHolder dataHolderVar;
private YourDataHolder() { }
public void storeDataToThreadLocal (String userName) {
dataVariable.set(userName);
}
public String readDataFromThreadLocal () {
if (dataVariable.get() != null) {
return (String) dataVariable.get();
}
}
public static ServiceVersionHolder getInstance () {
if (dataHolderVar == null) {
dataHolderVar = new YourDataHolder();
}
return dataHolderVar;
}
}
Upvotes: 0
Reputation: 533520
Do you mean something like this?
private static final ThreadLocal<AtomicInteger> COUNTER = new ThreadLocal<AtomicInteger>() {
@Override
protected AtomicInteger initialValue() {
return new AtomicInteger();
}
};
public static int incrementAndGet() {
return COUNTER.get().incrementAndGet();
}
Upvotes: 0
Reputation: 7302
Your target class shall not be singleton, but you must access it just using the ThreadLocal, and creating a new instance if ThreadLocal instance is empty (doesn't hold a reference to an instance of your target object).
Another solution is to make your Target class singleton, and hold its state in ThreadLocal variables.
Upvotes: 2
Reputation: 25873
Use synchronized for multithreading.
public static synchronized final Singleton getInstance() {
This way the threads will "lock" the method: only one thread will be allowed to enter the method at a time, other threads will block until the method is unlocked (the thread executing it leaves). You won't have those concurrency issues.
Also you don't need 2 singletons (which IMHO actually makes no sense and defeats the very own purpose of a singleton...).
Upvotes: -1