ThreadLocal自我见解

背景

threadlocal变量 是一种线程级全局的变量(普通的全局变量是进程级全局),就是在一个线程中,任何方法、函数能访问到这个threadlocal对象关联的对象,只要没有重新设置,都是同一个对象,变量作用域介于全局变量和局部变量之间,每个线程访问都是获取到threadlocal中对应得变量副本,线程之间互不干扰(线程安全情况下)。

1.全局变量(global variable),比如类的静态属性(加static关键字),在类的整个生命周期都有效;

2.局部变量(local variable),比如在一个方法中定义的变量,作用域只是在当前方法内,方法执行完毕后,变量就销毁(释放)了;

  使用全局变量,当多个线程同时修改静态属性,就容易出现并发问题,导致脏数据;而局部变量一般来说不会出现并发问题(在方法中开启多线程并发修改局部变量,仍可能引起并发问题);

  再看ThreadLocal,从名称上就能知道,它可以用来保存局部变量,只不过这个“局部”是指“线程”作用域,也就是说,该变量在该线程的整个生命周期中有效。

本质
threadlocal是一个数据结构和List Map等java数据结构地位是一样的,具体实现是每个“线程对象”中有一个Map,线程存活期中,这个MAP不会被释放,也不会被重置;
线程使用threadlocal时,首先要设置这个threadlocal,设置的时候,以threadlocal这个对象为KEY,以被设置的对象为value,存放到这个线程的MAP中,
后面的代码获取这个threadlocal对象的关联对象时,就以threadlocal对象为KEY 到当前线程的MAP中获取那个先前设置的对象,这样就能在线程中(不同函数中)共享这个被设置的对象了,实现跨函数访问能力。
虽然不同线程设置同一个threadlocal时,KEY是相同的,不过是用不同的MAP,而且访问的时候 也是到不同的MAP中找对象,所以只能访问到本线程设置的对象

说白了,就是各自玩各自得!不建议在线程池中用threadlocal,因为线程池得线程能重复使用不回收,这样可能就会导致脏数据。

例:

 

public class ThreadLocalTest {

    ThreadLocal<String> lal = ThreadLocal.withInitial(()->"8888");  //第一种得默认初始化
    ThreadLocal<String> local = new ThreadLocal<String>(){//第二种默认初始化
        @Override
        protected String initialValue() {
            return "6666";
        }
    };
    private String num;

    private String word;

    public String getWord() {
        return lal.get();
    }

    public void setWord(String word) {
        lal.set(word);
    }

    public String getNum() {
        return local.get();
    }

    public void setNum(String num) {
        local.set(num);
    }

    public static void main(String[] args){
        ThreadLocalTest test = new ThreadLocalTest();
        System.out.println("初始值--num----"+test.getNum());
        System.out.println("初始值--word----"+test.getWord());

        for (int i=0;i<50;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    test.setNum(Thread.currentThread().getName()+"----set");
                    System.out.println("_____________");

                    System.out.println(Thread.currentThread().getName()+"_____"
                            +test.getNum());
                }
            });
            t1.start();
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

ThreadLocal不能解决线程安全问题

例:

public class ThreadLocalDear {
    private static ThreadLocal<Integer> test = ThreadLocal.withInitial(()->0);
    public static Integer a = 0;

    public static Integer getA() {
        return a;
    }

    public static void setA(Integer a) {
        ThreadLocalDear.a = a;
    }

    public static void main(String[] args){
        ThreadLocalDear dear = new ThreadLocalDear();
        for (int i = 0; i < 10; i++) {
            new Thread() {
                public void run() {
                    //1
                    a = test.get();
                    a++;

                    //2
                    test.set(a);
                    System.out.println("plus:" + Thread.currentThread().getName() + ": " + test.get());
                }
            }.start();
        }
    }
}

输出:

plus:Thread-1: 1
plus:Thread-0: 1
plus:Thread-2: 1
plus:Thread-3: 1
plus:Thread-4: 1
plus:Thread-5: 1
plus:Thread-6: 1
plus:Thread-7: 1
plus:Thread-9: 1
plus:Thread-8: 1

在代码“1”的时候,每一个线程都会将threadLocal的初始值0赋值给共享变量a,因为每一个线程从threadLocal.get()拿到的值都是自己threadLocal保存的。所以,就没有所以了。  
所以对于共享变量a来讲,每个线程都会首先将自己threadLocal里面的初始值0赋值给a,然后将共享变量a+1,然后将a+1的值设置到自己的ThreadLocalMap中,其他线程就访问不到了。下一个线程来的时候又会将自己threadLocal里面的初始值0赋值给a,然后将 a+1,然后... 如此周而复始。a只是被在0和1之间改来改去,最终放到每一个线程的threadLocal里面的a+1的值就不再共享。对于a这个共享变量来讲,如果在for循环创建的某线程A即将执行代码“2”之前,被其他for循环以外的某个线程改了一把。那么存到线程A的ThreadLocalMap中的值就是被改过的值了。

Java的ThreadLocal不是设计用来解决多线程安全问题的,事实证明也解决不了,共享变量a还是会被随意更改。ThreadLocal无能为力。所以,一般用ThreadLocal都不会将一个共享变量放到线程的ThreadLocal中。一般来讲,存放到ThreadLocal中的变量都是当前线程  
本身就独一无二的一个变量。其他线程本身就不能访问,存到ThreadLocal中只是为了方便在程序中同一个线程之间传递这个变量。  
所以,ThreadLocal和解决线程安全没有关系。   

运用

1、登陆信息  session管理

2、数据库链接(链接一次,重复使用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值