Java多线程10:ThreadLocal的作用及使用

来源:互联网 发布:在线seo外链工具软件 编辑:程序博客网 时间:2024/05/29 16:31

ThreadLocal的作用

从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是是线程自己要存储的对象,其他线程不需要去访问,也是访问不到的。各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocal中的值都是不同的对象。

至于为什么要使用ThreadLocal,不妨这么考虑这个问题。Java Web中,写一个Servlet:

复制代码
public class Servlet extends HttpServlet{    protected void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException    {        this.doGet(request, response);    }    protected void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException    {            }}
复制代码

我在一个普通JavaBean内想拿到这个HttpServletRequest,但是无法通过参数传递的方式:

复制代码
public class OperateRequest{    public String operateRequest()    {        return null;    }}
复制代码

这时候怎么办?第一个解决方案,Servlet类中定义一个全局的HttpServletRequest,至于怎么定义就随便了,可以定义成静态的,也可以定义成非静态的但是对外提供setter/getter,然后operateRequest()方法每次都取这个全局的HttpServletRequest就可以了。

不否认,这是一种可行的解决方案,但是这种解决方案有一个很大的缺点:竞争。既然HttpServletRequest是全局的,那势必要引入同步机制来保证线程安全性,引入同步机制意味着牺牲响应给用户的时间----这在注重与用户之间响应的Java Web中是难以容忍的。

所以,我们引入ThreadLocal,既然ThreadLocal.ThreadLocalMap是线程独有的,别的线程访问不了也没必要访问,那我们通过ThreadLocal把HttpServletRequest设置到线程的ThreadLocal.ThreadLocalMap里面去不就好了?这样,在一次请求中哪里需要用到HttpServletRequest,就使用ThreadLocal的get()方法就把这个HttpServletRequest给取出来了,是不是一个很好的解决方案呢?

 

ThreadLocal使用

忘记上面那个复杂的问题,我们来看一下ThreadLocal的简单使用,首先ThreadLocal肯定是全局共享的:

public class Tools{    public static ThreadLocal<String> t1 = new ThreadLocal<String>();}

写一个线程往ThreadLocal里面塞值:

复制代码
public class ThreadLocalThread extends Thread{    private static AtomicInteger ai = new AtomicInteger();        public ThreadLocalThread(String name)    {        super(name);    }        public void run()    {        try        {            for (int i = 0; i < 3; i++)            {                Tools.t1.set(ai.addAndGet(1) + "");                System.out.println(this.getName() + " get value--->" + Tools.t1.get());                Thread.sleep(200);            }        }        catch (InterruptedException e)        {            e.printStackTrace();        }    }}
复制代码

写个main函数,启动三个ThreadLocalThread:

复制代码
public static void main(String[] args) throws Exception    {        ThreadLocalThread a = new ThreadLocalThread("ThreadA");        ThreadLocalThread b = new ThreadLocalThread("ThreadB");        ThreadLocalThread c = new ThreadLocalThread("ThreadC");        a.start();        b.start();        c.start();    }
复制代码

看一下运行结果:

复制代码
ThreadA get value--->1ThreadC get value--->2ThreadB get value--->3ThreadB get value--->4ThreadC get value--->6ThreadA get value--->5ThreadC get value--->8ThreadA get value--->7ThreadB get value--->9
复制代码

看到每个线程的里都有自己的String,并且互不影响----因为绝对不可能出现数字重复的情况。用一个ThreadLocal也可以多次set一个数据,set仅仅表示的是线程的ThreadLocal.ThreadLocalMap中table的某一位置的value被覆盖成你最新设置的那个数据而已,对于同一个ThreadLocal对象而言,set后,table中绝不会多出一个数据

 

ThreadLocal再总结

上一篇文章的最后有对ThreadLocal的工作原理进行总结,这里对ThreadLocal再次进行一个总结:

1、ThreadLocal不是集合,它不存储任何内容,真正存储数据的集合在Thread中。ThreadLocal只是一个工具,一个往各个线程的ThreadLocal.ThreadLocalMap中table的某一位置set一个值的工具而已

2、同步与ThreadLocal是解决多线程中数据访问问题的两种思路,前者是数据共享的思路后者是数据隔离的思路

3、同步是一种以时间换空间的思想,ThreadLocal是一种空间换时间的思想

4、ThreadLocal既然是与线程相关的,那么对于Java Web来讲,ThreadLocal设置的值只在一次请求中有效,是不是和request很像?因为request里面的内容也只在一次请求有效,对比一下二者的区别:

(1)ThreadLocal只能存一个值,一个Request由于是Map形式的,可以用key-value形式存多个值

(2)ThreadLocal一般用在框架,Request一般用在表示层、Action、Servlet

0 0
原创粉丝点击