ThreadLocal详解【使用场景】
转:
么是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详解【使用场景】的更多相关文章
- 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)
简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...
- android Handler机制之ThreadLocal详解
概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...
- Java并发编程:线程封闭和ThreadLocal详解
转载请标明出处: http://blog.csdn.net/forezp/article/details/77620769 本文出自方志朋的博客 什么是线程封闭 当访问共享变量时,往往需要加锁来保证数 ...
- ThreadLocal详解(实现多线程同步访问变量)
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...
- ThreadLocal详解
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...
- 并发系列(2)之 ThreadLocal 详解
本文将主要结合源码讲述 ThreadLocal 的使用场景和内部结构,以及 ThreadLocalMap 的内部结构:另外在阅读文本之前只好先了解一下引用和 HashMap 的相关知识,可以参考 Re ...
- ThreadLocal详解,ThreadLocal源码分析,ThreadLocal图解
本文脉路: 概念阐释 ----> 原理图解 ------> 源码分析 ------> 思路整理 ----> 其他补充. 一.概念阐述. ThreadLocal 是一个为 ...
- 【Java深入研究】7、ThreadLocal详解
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...
- ThreadLocal详解,处理成员变量线程不安全的情况
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...
随机推荐
- 网络编程实现简单的ssh
客户端:客户端实例 ---> 建立连接 ----> 发送内容 ---> 接受内容. import socket client = socket.socket() client.c ...
- C# 对象遍历 string类型 null转空字符串和去前后空格
using System; using System.Collections.Generic; namespace OA.Common.Extensions { /// <summary> ...
- 一篇关于ajax跨域问题的解决方案
这几天没事,我有一个好友,让我帮他做一个机器人对话demo, 我说 看看有没有时间(其实自己一脸懵逼) 然后百度了一下,发现了一个机器人 -(连接就不弄出来了,可以私底下交流) ,,我是用这个的 好 ...
- OpenLDAP 搭建入门
系统环境:CentOS 7 slapd版本:2.4.44 简介 OpenLDAP是一款轻量级目录访问协议,基于X.500标准的,支持TCP/IP协议,用于实现账号集中管理的开源软件,提供一整套安全的账 ...
- qjson中把记录或类型或泛型数组转换为json字符串
unit Unit4; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...
- python3:iterable, iterator, generator,抽象基类, itertools的使用。
目录: iterable对象 iterator对象, 数据类型Iterator类 数据类型Generator类. 生成器表达式 collections.abc:容器的抽象基类.用于判断具体类. ite ...
- R的数据结构--数组
数组:可以认为数组是矩阵的扩展,它将矩阵扩展到2维以上.如果给定的数组是1维的则相当于向量,2维的相当于矩阵. R语言中的数组元素的类型也是单一的,可以是数值型,逻辑型,字符型或复数型 参数解释 ar ...
- HTML5——5 HTML5 SVG
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]
题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边. 这题还是要考察Kruskal的贪心过程. 先跑一棵MST出来.然后考虑每条边. 如果他是非树边,要让他Kruskal的时候被选入,必 ...
- C# WebClient 的文件上传下载
上传文件 string path = openFileDialog1.FileName; WebClient wc = new WebClient(); wc.Credentials = Creden ...