1、ThreadLocal初识

  从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。
  我们可以得知ThreadLocal的作用是∶提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。

  • 线程并发:ThreadLocal只在多线程的环境下起作用
  • 传递数据:我们可以通过ThreadLocal在同一线程不同组件中传递公共数据
  • 线程隔离:每一个线程的变量都是独立的,不会相互影响

 

2、ThreadLocal的基本使用

(1)常用方法

多线程:ThreadLocal的基本使用_数据

(2)ThreadLocal的简单使用

多线程的不隔离性:

public class T1 {
    private String content;
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public static void main(String[] args) {
        T1 t1=new T1();
        for(int  i=0;i<5;i++){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    t1.setContent(Thread.currentThread().getName()+"的数据:");
                    System.out.println(Thread.currentThread().getName()+"---"+t1.getContent());
                }
            });
            thread.setName("线程"+i);
            thread.start();
        }
    }
}

测试结果:

线程1---线程1的数据:
线程0---线程1的数据:
线程2---线程2的数据:
线程3---线程3的数据:
线程4---线程4的数据:

将变量与当前线程绑定:

public class T1 {
    private String content;
    ThreadLocal<String> threadLocal=new ThreadLocal<>();
    public String getContent() {
        return threadLocal.get();
    }

    public void setContent(String content) {
        threadLocal.set(content);
    }

    public static void main(String[] args) {
        T1 t1=new T1();
        for(int  i=0;i<5;i++){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    t1.setContent(Thread.currentThread().getName()+"的数据:");
                    System.out.println(Thread.currentThread().getName()+"---"+t1.getContent());
                }
            });
            thread.setName("线程"+i);
            thread.start();
        }
    }
}

测试结果:

线程0---线程0的数据:
线程1---线程1的数据:
线程2---线程2的数据:
线程3---线程3的数据:
线程4---线程4的数据:

多个线程的数据是相互隔离的。在多线程的场景下,每一个线程的变量都相互独立。例如:线程1设置的变量是变量1,那么获取到的变量也是变量1。

(3)加锁

public class T1 {
    private String content;
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
    public static void main(String[] args) {
        T1 t1=new T1();
        for(int  i=0;i<5;i++){
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (T1.class){
                        t1.setContent(Thread.currentThread().getName()+"的数据:");
                        System.out.println(Thread.currentThread().getName()+"---"+t1.getContent());
                    }
                }
            });
            thread.setName("线程"+i);
            thread.start();
        }
    }
}

虽然ThreadLocal模式与synchronized关键字都用于处理多线程并梭访问变量的问题,不过两者处理问题的角度和思路不同。
多线程:ThreadLocal的基本使用_数据_02

 

 用ThreadLocal可以使得程序有更好的性能,因为ThreadLocal没有加锁

(4)案例

在银行转账的案例中:

传统解决方案:

保证service层和dao层的连接对象的一致,可以通过将service层的参数传递到dao层,但是会提高代码的耦合度

需要保证每一个线程的连接对象前后一致,也就是说线程1的连接对象对应连接1,线程2的连接对象对应连接2,可以通过加锁(synchronized)的方式保证线程的隔离,但是会降低程序的性能

ThreadLocal方式:

传递数据︰保存每个线程绑定的数据,在需要的地方可以直接获取,避免参数直接传递带来的代码耦合问题
线程隔离︰各线程之间的数据相互隔离却又具备并发性,避兔同步方式带来的性能损失

 

 

 

 

每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛