码迷,mamicode.com
首页 > 其他好文 > 详细

详细的ThreadLocal以及与synchronized的区别

时间:2020-07-20 22:51:42      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:throw   限制   同步机制   ble   线程并发   创建   并发   利用   处理   

ThreadLocal

概述

threadlocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据

ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。

做个不恰当的比喻,从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。

这里的这个比喻是不恰当的,实际上是ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。

ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。

ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文

作用

提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用

总结:
1.线程并发:在多线程并发的场景下(单线程是用不到ThreadLocal的)
2.传递数据:我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量(和域对象有点相似)
3.线程隔离:每个线程的变量都是独立的不会互相影响(ThreadLocal的核心)

基本使用

常用方法

方法声名 描述
ThreadLocal( ) 创建ThreadLocal对象
public void set(T value) 设置当前线程绑定的局部变量
public T get( ) 获取当前线程绑定的局部变量
public void remove( ) 移除当前线程绑定的局部变量

使用案例

演示问题:

/*
    需求:线程隔离
           在多线程并发的场景下,每个线程中的变量都是相互独立
           线程A:     设置(变量1)     获取(变量1)
           线程B:     设置(变量2)     获取(变量2)
 */
public class MyDemo01 {

    //变量
    private String content;

    public String getContent() {
        return content;
    }

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


    public static void main(String[] args) {
        MyDemo01 demo = new MyDemo01();

        //开启五个线程
        for (int i = 0; i < 5; i++) {

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    //每个线程:存一个变量,过一会取出这个变量
                    demo.setContent(Thread.currentThread().getName() + "的数据");
                    System.out.println("-----------------");
                    System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
                }
            });

            //设置线程名字
            thread.setName("线程"+i);
            thread.start();

        }
    }
}

结果显示:

技术图片

多运行几次,就会出现以上数据,每个线程存入的数据和取出的数据是不一致的,java中的线程调度是抢占式调度,本身具备随机性

这种情况就是线程不隔离

应该怎么解决呢?

利用ThreadLocal

技术图片

ThreadLocal是一个泛型类,绑定的变量类型是不受限制的

使用ThreadLocal改进之后的代码

/*
    需求:线程隔离
           在多线程并发的场景下,每个线程中的变量都是相互独立
           线程A:     设置(变量1)     获取(变量1)
           线程B:     设置(变量2)     获取(变量2)

    ThreadLocal:
        1.set():    将变量绑定到当前线程中
        2.get():    获取当前线程绑定的变量
 */
public class MyDemo01 {

    ThreadLocal<String> t1 = new ThreadLocal<>();

    //变量
    private String content;

    public String getContent() {
//        return content;
        String s = t1.get();
        return s;
    }

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

        //将变量content绑定到当前线程
        t1.set(content);
    }


    public static void main(String[] args) {
        MyDemo01 demo = new MyDemo01();

        //开启五个线程
        for (int i = 0; i < 5; i++) {

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    //每个线程:存一个变量,过一会取出这个变量
                    demo.setContent(Thread.currentThread().getName() + "的数据");
                    System.out.println("-----------------");
                    System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
                }
            });

            //设置线程名字
            thread.setName("线程"+i);
            thread.start();

        }
    }
}

再次运行,多运行几次,增加出现问题的几率

结果正常,哪怕加上thread.sleep(200); 结果也还是正常的

技术图片

ThreadLocal解决了线程隔离的这个需求

与 synchronized 的区别

使用synchronized也可以完成隔离线程的需求

public class MyDemo02 {

    //变量
    private String content;

    public String getContent() {
        return content;
    }

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


    public static void main(String[] args) throws InterruptedException {
        MyDemo02 demo = new MyDemo02();

        //开启五个线程
        for (int i = 0; i < 5; i++) {

            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    //每个线程:存一个变量,过一会取出这个变量
                    //使用synchronized代码块来完成需求
                    synchronized (MyDemo02.class){
                        demo.setContent(Thread.currentThread().getName() + "的数据");
                        System.out.println("-----------------");
                        System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
                    }
                }
            });

            //设置线程名字
            thread.setName("线程"+i);
            thread.start();
            thread.sleep(200);

        }
    }
}

那么ThreadLocal与synchronized的区别是什么呢?

技术图片

右边的代码加了synchronized锁,线程只能一个一个去执行,排队进行访问,效率低,让我们的程序失去了并发性

左边没有加锁,一样可以并发执行

虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题,

但是两者处理问题的角度和思路不同

synchronized ThreadLocal
原理 同步机制采用“以时间换空间”的方式,只提供了一份变量,让不同的线程排队访问 ThreadLocal采用“以空间换空间”的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰
侧重点 多个线程之间访问资源的同步 多线程中让每个线程之间的数据相互隔离

小结:

synchronized锁是解决线程的同步问题,线程失去并发性,效率低
ThreadLocal可以使程序拥有更高的并发性,能够保证程序执行的效率

详细的ThreadLocal以及与synchronized的区别

标签:throw   限制   同步机制   ble   线程并发   创建   并发   利用   处理   

原文地址:https://www.cnblogs.com/liqiliang1437/p/13347051.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!