ThreadLocal的使用
Posted iaiti
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal的使用相关的知识,希望对你有一定的参考价值。
在51CTO看到的一篇关于ThreadLocal的博客,前半部分写得很好,后面举的Student根本就没有意义,不同的线程拿到当前的Student,每个线程打印出来的肯定是自己Student的age变量。这个和ThreadLocal作用没有关系。只好再去Google找找。
发现了一篇写得比较好的博客,已邮件联系作者并得到作者同意(印度开发也挺厉害的,之前看到Jakod Jenkov写的并发的文章也很nice,也准备翻译,询问之后他说已经有网站翻译了他大部分的文章了,真是巧)。
原文地址:http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/
Java Thread Local —— 如何使用和事例代码
Thread Local是一个有趣并且有用的概念,但是大多数的Java开发者并不知道如何使用(是的,我自己当初面试的时候从见过这个词)。在这里,我会用代码例子介绍它是什么和什么时候用它。
因为刚开始理解它的概念有点难度,我尽可能简单地解释(结论:你不应该在开发项目的时候使用这些代码,要捉住概念并在此基础上修改!)
让我们开始。
什么是Thread Local?
Thread Local可以看成是一个访问域(scope of acess),像请求域或者是session域。它是一个线程域。你可以在Thread Local中设置任意的对象,那么这个对象将在访问这个对象的线程中既是全局又是局部。全局和局部!!?
让我解释一下:
存储在Thread Local的值在线程中是全局的,意味着他们可以在线程内部的任意位置都可以访问到。如果一个线程调用了多个类的方法,那么任意方法都可以看到其他方法在Thread Local设置的变量(因为他们在同一个线程中)。这个值不需要被显式地传递。这就像你在使用全局变量一样。
存储在Thread Local的值在线程中是局部的,意味着每一个线程拥有自己的Thread Local变量,一个线程不能访问和修改其他线程的Thread Local变量。
好了,这就是Thread Local的概念了,希望你理解了。
什么时候使用Thread Local?
我们看了前面部分讲的什么是Thread Local。现在让我们讨论一下你需要用到Thread Local的事例。
我展示一个用到Thread Local的用例。想一下,你有一个Servlet调用了一些业务方法。你需要为对该servlet的每个请求过程生成一个唯一的事务id,你需要将这个事务id传递到业务方法中。但这不是一种好的解决方法,代码冗余且没必要。
解决办法是你可以使用Thread Local,你可以生成一个事务id(可以再servlet中,最好在过滤器中生成),然后把它设进Thread Local中。接下来,无论是哪个servlet调用的业务方法,都可以从Thread Local中访问到业务id。
这个servlet可能每次服务于多个请求,因为每个请求由单独的线程处理,业务id对于每个线程来说是唯一的(局部),业务id对于线程的执行是可访问的(全局)。
(翻译者的看法,生成的事务id交给Thread Local处理,每个线程都有自己的业务id,针对属于自己的线程来说,业务id对自己线程里面的操作又是可见的。)
理解了?!
如何使用Thread Local?
Java提供了Thread Local类,你可以用它来set/get 线程域的变量。下面用代码示例来展示我前面说的那些。
Context.java,持有transactionid域。
public class Context
private String transactionId = null;
public String getTransactionId()
return transactionId;
public void setTransactionId(String transactionId)
this.transactionId = transactionId;
MyThreadLocal.java,作为持有Context对象的容器。
/**
* this class acts as a container to our thread local variables.
* @author vsundar
*
*/
public class MyThreadLocal
public static final ThreadLocal userThreadLocal = new ThreadLocal();
public static void set(Context user)
userThreadLocal.set(user);
public static void unset()
userThreadLocal.remove();
public static Context get()
return (Context) userThreadLocal.get();
上面代码中,在静态域里面创建了ThreadLocal类,这样在代码的其他部分就可以set/getThread Local变量。
创建main类,在thread local生成和设置transaction ID ,调用业务方法。
public class ThreadLocalDemo extends Thread
public static void main(String args[])
Thread threadOne = new ThreadLocalDemo();
threadOne.start();
Thread threadTwo = new ThreadLocalDemo();
threadTwo.start();
@Override
public void run()
// sample code to simulate transaction id
Context context = new Context();
context.setTransactionId(getName());
// set the context object in thread local to access it somewhere else
MyThreadLocal.set(context);
/* note that we are not explicitly passing the transaction id */
new BusinessService().businessMethod();
MyThreadLocal.unset();
最后,BusinessService.java可以读取Thread Local的值并使用。
public class BusinessService
public void businessMethod()
// get the context from thread local
Context context = MyThreadLocal.get();
System.out.println(context.getTransactionId());
最后输出:
Thread-0
Thread-1
你会看到,我们虽然没有显式地传递transaction id的值,值可以在business方法中访问到并且在控制台输出。而且,transaction id在每个线程中都不同(0和1)。
好了,就是这些了,我尽可能简单地解释它,你可以留下评论描述你的看法,如果你想为这个主题添加任何的东西,也留下你的评论。
译者继续写点东西,可能一路看下来你又会模糊了,你会思考什么全局局部在这个例子怎么没有?所谓transaction id传递不传递有什么用?
我再补全:
再写一个
public class BusinessServiceTwo
public void businessMethod()
// get the context from thread local
Context context = MyThreadLocal.get();
System.out.println("the second service is"+context.getTransactionId());
MyThreadDemo的run方法里面也写多一个方法
new BusinessServiceTwo().businessMethod();
这样就好理解了,所谓的局部,任意线程都不能看到其他线程的transaction id是什么。
所谓全局,同一个线程调用的不同业务逻辑,但是,他们的transaction id是一样的,全局。
那有什么用呢?
设想,如果我是银行,我要知道是谁在取钱,如果每次我要知道是谁在操作业务那么
我写的就是service(String name),service2(String name),这样是不是冗余了,而且也不准确,哪天我要把其他参数也传进去,是不是烦死了?
所以ThreadLocal来了。把这些属性放到一个类中,Thread存进这个类,每次业务逻辑调用的时候只需要
Context context = MyThreadLocal.get();
这样是不是简洁好多?
博客写得确实好,我再看一次之后,也真正弄懂了。
完。
以上是关于ThreadLocal的使用的主要内容,如果未能解决你的问题,请参考以下文章