Java并发编程ThreadLocal(三)|Java基础

200 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

概念

ThreadLocal的作用:提供线程内的局部变量,不同线程之间不会相互干扰,这种变量在线程的生命周期起作用,减少同一个线程内的多个函数或组件之间一些公共变量传递的复杂度。

总结:

  1. 线程并发:并发的场景下
  2. 传递数据:通过ThreadLocal在同一线程,不同组件传递公共变量
  3. 线程隔离: 每个线程的变量都是独立的,不会相互影响

基本使用

ThreadLocal JDK 包提供的,它提供了线程本 变量,也就是如果你创建了 ThreadLocal ,那么访问这个变 的每个线程都会有这个变量的一个本地副本 当多 个线程操作这个变量时,实际操作的是自己本地内 存里面 变量,从而避免了 线程安全 题。创建 ThreadLocal 变量后,每个线程都会复制 到自己的本地内。 常用方法 | 方法声明 | 描述 | | --- | --- | | ThreadLocal() |创建ThreadLocal | | public void set() | 设置当前线程绑定的变量 | | public T get() | 获取当前线程绑定的变量 | | public void remove() | 移除当前线程绑定的变量 |

public class MyDemo {
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public static void main(String[] args) {
        MyDemo myDemo = new MyDemo();
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                myDemo.setData(Thread.currentThread().getName() + "的数据");
                System.out.println("------------------------------------");
                System.out.println(Thread.currentThread().getName() + "---> " + myDemo.getData());
            },String.valueOf(i)).start();
        }
    }
}

image.png 我们可以看到在并发的场景下,线程是非隔离状态的,当前线程set的数据是可以被其他线程拿到的。

那什么是线程隔离呢?

在多线程并发的场景下每个线程中的变量都是相互独立的。

线程名设置数据获取数据
Thread-0setData()只能拿到在Thread-0里设置的数据
Thread-1setData()只能拿到在Thread-1里设置的数据

利用ThreadLocal的set()方法,设置仅属于当前线程的变量,当然获取的话同样需要调用ThreadLocal的get()方法。

public class MyDemo {
    private String data;
    private final ThreadLocal<String> threadLocal = new ThreadLocal<>();
    
    public String getData() {
        // 获取当前线程绑定的变量
        return threadLocal.get();
    }

    public void setData(String data) {
        //设置当前线程绑定的变量
        threadLocal.set(data);
    }

    public static void main(String[] args) {
        MyDemo myDemo = new MyDemo();
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                myDemo.setData(Thread.currentThread().getName() + "的数据");
                System.out.println(Thread.currentThread().getName() + "---> " + myDemo.getData());
            },String.valueOf(i)).start();
        }
    }
}

image.png    在使用ThreadLocal之后,每次取出的数据都是当前线程所绑定的数据。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal与Synchronized

   这个时候就该想到Synchronized不也同样可以实现这个效果么,但是我们加锁的方式必然引起性能问题。

虽然ThreadLocal和Synchronized都可以用于处理并发访问变量的问题,但是俩者的角度不同

SynchronizedThreadLocal
原理同步机制“以时间换空间” ,只提供一份变量,让线程排队访问“以空间换时间”为每一个线程提供一份变量副本,实现同时访问且或不干扰
侧重点多个线程之间访问资源同步多线程让每个线程之间的数据相互隔离