Arya
Arya

Reputation: 8985

Pass ThreadLocal class to another thread?

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

Answers (1)

D.B.
D.B.

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

Related Questions