Reputation: 8985
I'm using ThreadLocal within my Java program inorder to get and set certain data members through out the thread.
I have a class with the following content
public class ThreadLocalManager {
public static final ThreadLocal<String> accountUsername = new ThreadLocal<String>();
public static final ThreadLocal<String> accountPassword = new ThreadLocal<String>();
public static final ThreadLocal<Long> accountId = new ThreadLocal<Long>();
.....................
.....................
.....................
}
I have been using this with no problems in my multi threaded application. Now each thread will be creating another thread and I want ThreadLocalManager to be passed to the new thread that was created. How would this be done?
Upvotes: 1
Views: 4104
Reputation: 4713
EDIT: I modified my example code from my original suggestion (below) to use InheritableThreadLocal
and I find it to be much simpler so adding the updated code.
Here is the updated ThreadLocalManager:
package inheritableThreadLocal;
public class ThreadLocalManager {
public static final InheritableThreadLocal<String> accountUsername = new InheritableThreadLocal<String>();
public static final InheritableThreadLocal<String> accountPassword = new InheritableThreadLocal<String>();
public static final InheritableThreadLocal<Long> accountId = new InheritableThreadLocal<Long>();
}
I also updated Runner
(see original below) but now its only purpose is to print the values of the variables:
package inheritableThreadLocal;
public class Runner implements Runnable{
@Override
public void run() {
System.out.println("Inside Runner's run");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
}
}
Finally the updated class containing the main method:
package inheritableThreadLocal;
public class ThreadLocalMain {
public static void main(String[] args) {
System.out.println("At start of main");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
ThreadLocalManager.accountId.set(new Long(12345));
ThreadLocalManager.accountUsername.set("user1");
ThreadLocalManager.accountPassword.set("pass1");
System.out.println("In t1 run");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
Thread t2 = new Thread(new Runner());
t2.start();
}
});
t1.start();
}
}
Original Suggestion:
So you could create your new Thread
objects by using Runnable
objects. If you do that you can create custom objects that implement Runnable
and can hold the values of the ThreadLocal
variables until the new Thread
is started. Once the new Thread
starts (i.e. run
method is called) these custom Runnable
objects set the ThreadLocal
variables.
Here's a class with a main I created for this:
package threadLocal;
public class ThreadLocalMain {
public static void main(String[] args) {
System.out.println("At start of main");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
ThreadLocalManager.accountId.set(new Long(12345));
ThreadLocalManager.accountUsername.set("user1");
ThreadLocalManager.accountPassword.set("pass1");
System.out.println("In t1 run");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
Thread t2 = new Thread(new Runner(ThreadLocalManager.accountUsername.get(),
ThreadLocalManager.accountPassword.get(),
ThreadLocalManager.accountId.get()));
t2.start();
}
});
t1.start();
}
}
For completeness here's the ThreadLocalManager I used:
package threadLocal;
public class ThreadLocalManager {
public static final ThreadLocal<String> accountUsername = new ThreadLocal<String>();
public static final ThreadLocal<String> accountPassword = new ThreadLocal<String>();
public static final ThreadLocal<Long> accountId = new ThreadLocal<Long>();
}
Lastly, here is the custom Runnable
I created:
package threadLocal;
public class Runner implements Runnable{
private String userName, password;
private long acctId;
public Runner(String user, String pword, long accountId){
System.out.println("In Runner constructor");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
userName = user;
password = pword;
acctId = accountId;
}
@Override
public void run() {
System.out.println("Inside Runner's run");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
ThreadLocalManager.accountId.set(acctId);
ThreadLocalManager.accountUsername.set(userName);
ThreadLocalManager.accountPassword.set(password);
System.out.println("Inside Runner's run - after setting");
System.out.println(ThreadLocalManager.accountId.get());
System.out.println(ThreadLocalManager.accountUsername.get());
System.out.println(ThreadLocalManager.accountPassword.get());
}
}
This code passes the values of the ThreadLocal
variables into the Runner
instance and then the Runner
instance is used to create a new Thread
(which as you will see if you run the code has no values for the ThreadLocal
variables at first). Then the Runner
sets the ThreadLocal
variables and as you can see from the console output they match what t1 had.
Hope this helps!
Upvotes: 2