首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ThreadLocal

ThreadLocal

原创
作者头像
花落花相惜
修改2021-11-25 13:06:12
修改2021-11-25 13:06:12
4150
举报

ThreadLocal辨析

与Synchonized的比较

  • ThreadLocal和Synchonized都用于解决多线程并发訪问。

ThreadLocal与synchronized的本质差别

  • synchronized是利用锁的机制,使变量或代码块在某一时该仅仅能被一个线程訪问。
  • ThreadLocal为每个线程都提供了变量的副本,使得每个线程在某一时间訪问到的并非同一个对象,这样就隔离了多个线程对数据的数据共享。

ThreadLocal的使用

ThreadLocal类接口很简单,只有4个方法

代码语言:txt
复制
            • void set(Object value)   设置当前线程的线程局部变量的值。
代码语言:txt
复制
            • public Object get()  该方法返回当前线程所对应的线程局部变量。
代码语言:txt
复制
            • public void remove()  将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
代码语言:txt
复制
            • protected Object initialValue()
代码语言:txt
复制
    返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
代码语言:txt
复制
    public final static ThreadLocal<String> RESOURCE = new ThreadLocal<String>();RESOURCE代表一个能够存放String类型的ThreadLocal对象。此时不论什么一个线程能够并发访问这个变量,对它进行写入、读取操作,都是线程安全的。

image.png

image.png

image.png

上面先取到当前线程,然后调用getMap方法获取对应的ThreadLocalMap,ThreadLocalMap是ThreadLocal的静态内部类,然后Thread类中有一个这样类型成员,所以getMap是直接返回Thread的成员。

看下ThreadLocal的内部类ThreadLocalMap源码:

image.png

可以看到有个Entry内部静态类,它继承了WeakReference,总之它记录了两个信息,一个是ThreadLocal<?>类型,一个是Object类型的值。getEntry方法则是获取某个ThreadLocal对应的值,set方法就是更新或赋值相应的ThreadLocal对应的值。

image.png

image.png

回顾我们的get方法,其实就是拿到每个线程独有的ThreadLocalMap

然后再用ThreadLocal的当前实例,拿到Map中的相应的Entry,然后就可以拿到相应的值返回出去。当然,如果Map为空,还会先进行map的创建,初始化等工作。

  • 示例
代码语言:txt
复制
 static ThreadLocal<String> threadLocal = new ThreadLocal<>();
代码语言:txt
复制
    static ThreadLocal<Integer> threadLocal2 = new ThreadLocal<>();
代码语言:txt
复制
//  static MyThreadLocal<String> threadLocal = new MyThreadLocal<>();
代码语言:txt
复制
    /**
代码语言:txt
复制
     * 运行3个线程
     */
    public void StartThreadArray(){
        Thread[] runs = new Thread[3];
        for(int i=0;i<runs.length;i++){
            runs[i]=new Thread(new TestThread(i));
        }
        for(int i=0;i<runs.length;i++){
            runs[i].start();
        }
    }
    
代码语言:txt
复制
    /**
代码语言:txt
复制
     *类说明:测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
代码语言:txt
复制
     */
代码语言:txt
复制
    public static class TestThread implements Runnable{
代码语言:txt
复制
        int id;
代码语言:txt
复制
        public TestThread(int id){
代码语言:txt
复制
            this.id = id;
代码语言:txt
复制
        }
代码语言:txt
复制
        public void run() {
代码语言:txt
复制
            String threadName = Thread.currentThread().getName();
代码语言:txt
复制
            threadLocal.set("线程"+id);
代码语言:txt
复制
            if(id==1) {
代码语言:txt
复制
                threadLocal2.set(id);//线程1才会执行
代码语言:txt
复制
            }
代码语言:txt
复制
            System.out.println(threadName+":"+threadLocal.get());
代码语言:txt
复制
        }
代码语言:txt
复制
    }
代码语言:txt
复制
    public static void main(String[] args){
代码语言:txt
复制
        UseThreadLocal test = new UseThreadLocal();
代码语言:txt
复制
        test.StartThreadArray();
代码语言:txt
复制
    }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadLocal辨析
    • 与Synchonized的比较
    • ThreadLocal与synchronized的本质差别
    • ThreadLocal的使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档