转:

么是ThreadLocal

根据JDK文档中的解释:ThreadLocal的作用是提供线程内的局部变量,这种变量在多线程环境下访问时能够保证各个线程里变量的独立性。

从这里可以看出,引入ThreadLocal的初衷是为了提供线程内的局部变量

ThreadLocal 不是一个线程,而是一个线程的本地化对象。当某个变量在使用 ThreadLocal 进行维护时,ThreadLocal 为使用该变量的每个线程分配了一个独立的变量副本。

每个线程可以自行操作自己对应的变量副本,而不会影响其他线程的变量副本。

API 方法

ThreadLocal 的 API 提供了如下的 4 个方法。

1)protected T initialValue()

返回当前线程的局部变量副本的变量初始值。


2)T get()

返回当前线程的局部变量副本的变量值,如果此变量副本不存在,则通过 initialValue() 方法创建此副本并返回初始值。


3)void set(T value)

设置当前线程的局部变量副本的变量值为指定值。


4)void remove()

删除当前线程的局部变量副本的变量值。


在实际使用中,我们一般都要重写 initialValue() 方法,设置一个特定的初始值。

关于initialValue的初始化。本人尝试了多种方式:

1
2
3
4
5
6
7
8
//new ThreadLocal方式:不推荐
       final ThreadLocal<String> commandThreads = new ThreadLocal<String>() {
           @Override
           protected String initialValue() {
               return "execute :"+System.currentTimeMillis();
           }
       };
       System.out.println(commandThreads.get());

  

1
2
3
4
5
//withInitial方式:
        ThreadLocal<String> commandThreadnew =
//             ThreadLocal.withInitial(()-> "execute :"+System.currentTimeMillis());
                ThreadLocal.withInitial(()->new String("execute :"+System.currentTimeMillis()));
        System.out.println(commandThreadnew.get());

  

1
2
3
4
5
6
7
8
9
10
//(new Supplier<String>(){}方式 推荐
       ThreadLocal<String> commandThreadnew1 =
               ThreadLocal.withInitial(new Supplier<String>() {
                   @Override
                   public String get() {
                       return  "execute :"+System.currentTimeMillis();
                   }
               });
 
       System.out.println(  commandThreadnew1.get());

  

以下是关于ThreadLocal 解决多线程变量共享问题:

存在争议点:

ThreadLocal到底能不能解决共享对象的多线程访问问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.wuxianjiezh.demo.threadpool;
 
public class MainTest {
 
    public static void main(String[] args) {
        Bank bank = new Bank();
        Thread xMThread = new Thread(() -> bank.deposit(200), "小明");
        Thread xGThread = new Thread(() -> bank.deposit(200), "小刚");
        Thread xHThread = new Thread(() -> bank.deposit(200), "小红");
        xMThread.start();
        xGThread.start();
        xHThread.start();
    }
}
 
class Bank {
 
    private int money = 1000;
 
    public void deposit(int money) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + "--当前账户余额为:" + this.money);
        this.money += money;
        System.out.println(threadName + "--存入 " + money + " 后账户余额为:" + this.money);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  运行结果:存在多线程输出结果混乱

1
2
3
4
5
6
小明--当前账户余额为:1000
小红--当前账户余额为:1000
小红--存入 200 后账户余额为:1400
小刚--当前账户余额为:1000
小刚--存入 200 后账户余额为:1600
小明--存入 200 后账户余额为:1200

  

使用 ThreadLocal 保存对象的局部变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MainTest {
 
    public static void main(String[] args) {
        Bank bank = new Bank();
        Thread xMThread = new Thread(() -> bank.deposit(200), "小明");
        Thread xGThread = new Thread(() -> bank.deposit(200), "小刚");
        Thread xHThread = new Thread(() -> bank.deposit(200), "小红");
        xMThread.start();
        xGThread.start();
        xHThread.start();
    }
}
 
class Bank {
 
    // 初始化账户余额为 100
    ThreadLocal<Integer> account = ThreadLocal.withInitial(new Supplier<Integer>() {
        @Override
        public Integer get() {
            return 1000;
        }
    });
 
    public void deposit(int money) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + "--当前账户余额为:" + account.get());
        account.set(account.get() + money);
        System.out.println(threadName + "--存入 " + money + " 后账户余额为:" + account.get());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  运行结果为:

1
2
3
4
5
6
7
小明--当前账户余额为:1000
小红--当前账户余额为:1000
小红--存入 200 后账户余额为:1200
小刚--当前账户余额为:1000
小刚--存入 200 后账户余额为:1200
小明--存入 200 后账户余额为:1200
可以看到,我们要的效果达到了。各线程间同时操作自己的变量,相互间没有影响。

  

ThreadLocal 与 Thread 同步机制的比较

  • 同步机制采用了以时间换空间方式,通过对象锁保证在同一个时间,对于同一个实例对象,只有一个线程访问。

  • ThreadLocal 采用以空间换时间方式,为每一个线程都提供一份变量,各线程间同时访问互不影响。

转载请注明出处:https://segmentfault.com/a/1190000009236777

纸上得来终觉浅 绝知此事要躬行

ThreadLocal详解【使用场景】的更多相关文章

  1. 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)

    简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...

  2. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  3. Java并发编程:线程封闭和ThreadLocal详解

    转载请标明出处: http://blog.csdn.net/forezp/article/details/77620769 本文出自方志朋的博客 什么是线程封闭 当访问共享变量时,往往需要加锁来保证数 ...

  4. ThreadLocal详解(实现多线程同步访问变量)

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...

  5. ThreadLocal详解

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...

  6. 并发系列(2)之 ThreadLocal 详解

    本文将主要结合源码讲述 ThreadLocal 的使用场景和内部结构,以及 ThreadLocalMap 的内部结构:另外在阅读文本之前只好先了解一下引用和 HashMap 的相关知识,可以参考 Re ...

  7. ThreadLocal详解,ThreadLocal源码分析,ThreadLocal图解

    本文脉路: 概念阐释 ---->  原理图解  ------> 源码分析 ------>  思路整理  ----> 其他补充. 一.概念阐述. ThreadLocal 是一个为 ...

  8. 【Java深入研究】7、ThreadLocal详解

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...

  9. ThreadLocal详解,处理成员变量线程不安全的情况

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...

随机推荐

  1. miguowangluozhan

    加紧备战 美国欲将全球拖入网络战争 人民日报 06-1405:01 去年,美国国防部发布的网络空间战略强调了“前沿防御(Defense forward)”理念.这被外界解读为美国军方将在他国而非美国本 ...

  2. Centos使用光盘yum源

    yum查看所有源 yum repolist all 方法一:本机使用光盘源安装软件的设置 mkdir /media/cdrom mount /dev/cdrom  /media/cdrom vim / ...

  3. CF 976F 递增容量最大流

    给你一个二分图 要求你求出对于k=[0~Mindegree] 每个点的度数至少为k所需要的最少边数 并输出方案 如果是单个询问的话 直接跑一个下界网络流即可 但是有多个询问 重建图强行跑不行 反过来考 ...

  4. Python3+Appium学习笔记04-自动下载apk

    在项目中,app更新后,都会发布新的apk版本,然后去蒲公英对应的网站上扫码下载对应的apk进行测试.所以就在想,通过app参数进行安装时,是否可以先通过代码去拉取一遍最新的apk安装包. ​ 因为学 ...

  5. Linux gdb调试及后台程序问题

    https://blog.csdn.net/lengchanguo/article/details/50481533 转? 问题是后台& 调试

  6. [原创]在Windows平台使用msys2、mingw64和vscode编写和调试C/C++代码

    相关名词就不解释了,这里主要讲讲在vscode里怎么配,这里假设大家相关工具已经装好. 题外话:里面的大多数坑都是windows平台和linux平台的差异造成的,如果在linux平台配置,应该会顺利很 ...

  7. jQuery基础 (一)—样式篇

    jQuery的优势 jQuery有很多特性和工具方法

  8. Cow Hopscotch (单调队列 + DP)

    链接:https://ac.nowcoder.com/acm/contest/1113/K来源:牛客网 The cows have reverted to their childhood and ar ...

  9. 单例模式(Singleton)的同步锁synchronized

    单例模式,有“懒汉式”和“饿汉式”两种. 懒汉式 单例类的实例在第一次被引用时候才被初始化. public class Singleton { private static Singleton ins ...

  10. 在laravel5.8中集成swoole组件----用协程实现的服务端和客户端(nginx配置篇章)

    laravel项目中的配置  原文出处:https://laravelacademy.org/post/19700.html,感谢原文作者让laravel这款可爱的php框架,进入了高并发的殿堂 如果 ...