Multi-Thread 2---ThreadLocal

1. what is ThreadLocal

Thread local is not a thread. It's more like "thread local variable", it's a container that store thread related variables, so that each thread has it's own copy of this variable. More specifily, When one thread starts, we may want this thread has it's own scope of data(transactionId =1, name=xxx), and when another thread runs, it also has it's own copy of data. So we need to use ThreadLocal. 

Consider "synchronized", we want to use synchronized because we want many running threads share the same variable, in order not to damage the variable, we use synchronizd to let them use the variable in turn. ThreadLocal is the other way around, we want each one thread has its own variable and other thread can never change or attach it.

We should create a ThreadLocal instance in a thread. so this variable can be accessed everywhere whenever the thread needs it. For example, a thread may execute many other methods from other classes, in all these methods, we don't need to pass a parameter, in order to get the variable and change it.  We can just use ThreadLocal.get() method in these methods. because at runtime, GVM knows which variable we can calling exactly: it's this running thread's variable. Each ThreadLocal can only store one variable. if we want to store many variables, we can let ThreadLocal store class instance and this instance can have many variables.

2. how to use ThreadLocal

Consider you have a Servlet which calls some business methods. You have a requirement to generate a unique transaction id for each and every request this servlet process and you need to pass this transaction id to the business methods, for logging purpose. One solution would be passing this transaction id as a parameter to all the business methods. But this is not a good solution as the code is redundant and unnecessary.

To solve this ,first we have a data class context, it has transactionID, name 

public class Context {

    private String transactionId = null;
    private String username = null;
	private Integer age = null;
    
    public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getTransactionId() {
		return transactionId;
	}

	public void setTransactionId(String transactionId) {
		this.transactionId = transactionId;
	}

        /* getters and setters here */


}



Then create a MyThreadScopeDate, as a singleten, to make it Thread Local, we create a ThreadLocal instance to store context instance

/**
 * this class is put the needed data and a threadLocal together as a singleton.
 * so in each business method, we can get the instance and get or put data, and 
 * also make it threadlocal.
 * @author huantao
 *
 */
public class MyThreadScopeData {

    private static final ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
    private Context context;

	private MyThreadScopeData(){}
    
    
    public static MyThreadScopeData getThreadLocalInstance() {
    	MyThreadScopeData instance = map.get();
    	if(instance == null){
    		instance = new MyThreadScopeData();
    		map.set(instance);
    	}
    	return instance;
	}
    
    public Context getContext() {
		return context;
	}


	public void setContext(Context context) {
		this.context = context;
	}

}

Third, we have the Business model that do all kinds of works that will be called by thread, so they will use the each thread's local variable. but we don't need pass each running thread's variable to each method, which is horrible and also can't be realized. We just need to call MyTreadScopeData to get the thread related variable

public class BusinessModel {

	public void dowork(){
		MyThreadScopeData data = MyThreadScopeData.getThreadLocalInstance();
		
		Context context = data.getContext();
        System.out.println(context.getTransactionId());
	}

}

Forth. we can write the main code, under each thread we should craete a MyThreadScopeData variable, to set it's own data there, and can be called and modified every where else to do the work in other business classes.

public class MyThreadLocalTest extends Thread {

    public static void main(String args[]) {

        Thread threadOne = new MyThreadLocalTest();
        threadOne.start();

        Thread threadTwo = new MyThreadLocalTest();
        threadTwo.start();
    }

    @Override
    public void run() {
        // sample code to simulate transaction id
        Context context = new Context();
        int data = new Random().nextInt();
        context.setTransactionId(getName()+"  who and how:"+data);
        // set the context object in thread local to access it somewhere else
        MyThreadScopeData instance = MyThreadScopeData.getThreadLocalInstance();
        instance.setContext(context);
 
        /* let business model do the work without passing many thread related parameters */
        new BusinessModel().dowork();

    }
}



Reference see:
http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/
http://lavasoft.blog.51cto.com/62575/51926/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值