Java Concurrency - ThreadLocal, 本地线程变量
共享数据是多线程应用最常见的问题之一,但有时我们需要为每个线程保存一份独立的变量。Java API 提供了 ThreadLocal 来解决这个问题。
一个 ThreadLocal 作用的例子:
import java.util.Date; public class Main { public static void main(String[] args) {
Runnable task = new Runnable() { private ThreadLocal<Date> dateVar = new ThreadLocal<Date>(); public void run() {
dateVar.set(new Date());
System.out.printf("%s, GET dateVar: %s\n", Thread.currentThread().getName(), dateVar.get());
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s, FINAL dateVar: %s\n", Thread.currentThread().getName(), dateVar.get());
}
}; for (int i = 0; i < 3; i++) {
String threadName = "Thread" + (i + 1);
Thread thread = new Thread(task, threadName);
thread.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}
观察运行结果:
Thread1, GET dateVar: Fri Oct 14 22:06:33 CST 2016
Thread2, GET dateVar: Fri Oct 14 22:06:34 CST 2016
Thread3, GET dateVar: Fri Oct 14 22:06:35 CST 2016
Thread1, FINAL dateVar: Fri Oct 14 22:06:33 CST 2016
Thread2, FINAL dateVar: Fri Oct 14 22:06:34 CST 2016
Thread3, FINAL dateVar: Fri Oct 14 22:06:35 CST 2016
可以看到每个线程都共用一个 Task 实例,线程之间间隔 1 秒启动。线程执行 run 方法的时候首先将 dateVar 的值设置为系统当前时间并打印 dateVar 值,然后线程会休眠 5 秒,最后再打印 dateVar 的值。注意到 run 方法设置 dateVar 值与最后打印 dateVar 值间隔 5 秒,而下一个线程启动时只间隔 1 秒,在当前线程打印 dateVar 之前,下个线程甚至是下下个线程已经重置 dateVar 的值,但是每个线程最后打印 dateVar 值的时候仍然是显示该线程最初设置的值。可见,每个线程中的 dateVar 并不会被其他线程所干扰。
再看下没有使用 ThreadLocal 的情况。
import java.util.Date; public class Main2 { public static void main(String[] args) {
Runnable task = new Runnable() { private Date dateVar; public void run() {
dateVar = new Date();
System.out.printf("%s, GET dateVar: %s\n", Thread.currentThread().getName(), dateVar);
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s, FINAL dateVar: %s\n", Thread.currentThread().getName(), dateVar);
}
}; for (int i = 0; i < 3; i++) {
String threadName = "Thread" + (i + 1);
Thread thread = new Thread(task, threadName);
thread.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
观察运行结果:
Thread1, GET dateVar: Fri Oct 14 22:17:38 CST 2016
Thread2, GET dateVar: Fri Oct 14 22:17:39 CST 2016
Thread3, GET dateVar: Fri Oct 14 22:17:40 CST 2016
Thread1, FINAL dateVar: Fri Oct 14 22:17:40 CST 2016
Thread2, FINAL dateVar: Fri Oct 14 22:17:40 CST 2016
Thread3, FINAL dateVar: Fri Oct 14 22:17:40 CST 2016
可以看到,当直接使用 Date 类型时,线程最终打印 dateVar 的值与最初设置的值不一致。这个是因为所有的线程共享一个 Task 实例,所以 dateVar 是共享数据,在多个线程竞争时,造成数据不一致。
ThreadLocal 的初始化
可以通过覆盖 initialValue 方法初始化 ThreadLocal 的值。
ThreadLocal<Date> dateVar = new ThreadLocal<Date>() {
@Override
protected Date initialValue() {
return new Date();
}
};
InheritableThreadLocal
如果在线程 A 创建了子线程 B,那么线程 A 和 线程 B 都是各自维护一份 ThreadLocal 值,线程 A 的 ThreadLocal 值不会传递给子线程 B。Java API 提供了 InheritableThreadLocal 类,它是 ThreadLocal 的子类。如果使用 InheritableThreadLocal,那么在线程 A 创建子线程 B,线程 A 和 线程 B 仍然都是各自维护一份 InheritableThreadLocal 值,但是现场 A 的 InheritableThreadLocal 值则会传递给子线程 B。可以重写 childValue 方法修改从父现场继承的 InheritableThreadLocal 值。
public static ThreadLocal<Date> dateVar = new InheritableThreadLocal<Date>() {
protected Date initialValue() {
return new Date();
}; protected Date childValue(Date parentValue) {
return new Date(parentValue.getTime() + 1000L);
};
};
Java Concurrency - ThreadLocal, 本地线程变量的更多相关文章
- Java 类 ThreadLocal 本地线程变量
前言:工作中将要使用ThreadLocal,先学习总结一波.有不对的地方欢迎评论指出. 定义 ThreadLocal并不是一个Thread,而是Thread的局部变量.这些变量不同于它们的普通对应物, ...
- ThreadLocal本地线程变量的理解
一般的Web应用划分为展现层.服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用.在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程. ...
- ThreadLocal = 本地线程?
一.定义 ThreadLocal是JDK包提供的,从名字来看,ThreadLocal意思就是本地线程的意思. 1.1 是什么? 要想知道他是个啥,我们看看ThreadLocal的源码(基于JDK 1. ...
- Flask中的ThreadLocal本地线程,上下文管理
先说一下和flask没有关系的: 我们都知道线程是由进程创建出来的,CPU实际执行的也是线程,那么线程其实是没有自己独有的内存空间的,所有的线程共享进程的资源和空间,共享就会有冲突,对于多线程对同一块 ...
- java concurrency: ThreadLocal及其实现机制
转载:http://shmilyaw-hotmail-com.iteye.com/blog/1703382 ThreadLocal概念 从字面上来理解ThreadLocal,感觉就是相当于线程本地的. ...
- Java线程变量问题-ThreadLocal
关于Java线程问题,在博客上看到一篇文章挺好的: https://blog.csdn.net/w172087242/article/details/83375022#23_ThreadLocal_1 ...
- 深入研究java.lang.ThreadLocal类(转)
引用:http://lavasoft.blog.51cto.com/62575/51926/ 一.概述 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并 ...
- 深入研究java.lang.ThreadLocal类
一.概述 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许 ...
- Java多线程——ThreadLocal类
一.概述 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名 ...
随机推荐
- Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)
题目链接:http://codeforces.com/problemset/problem/691/D 给你n个数,各不相同,范围是1到n.然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无 ...
- python 实现冒泡排序与快速排序 遇到的错误与问题
今天看了兄弟连php里面的冒泡排序与快速排序,想了下应该可以用python实现. 冒泡排序函数: def mysort(x): len1 = len(x) for i in range(len1-1, ...
- Hibernate查询效率对比
查询已知表名的实体时推荐使用getHibernateTemplate().executeWithNativeSession() + SQLQuery方式. 以下测试使用JUnit进行,仅查询一次,查询 ...
- DuiLib(三)——控件消息
上一篇讲了控件创建,这篇说说控件消息.directui的中心思想是在真实窗口之上画出所有控件,那这些控件是如何获取各自消息的? 通过第一篇的示例可以看到窗口消息的传递过程: CWindowWnd::_ ...
- PS-常用操作
快捷键 设置图片的大小:ctrl+t 放大缩小:ctrl+空格+“+or-”
- 使用CKEditor编辑器进行文本编辑
首先下载CKEditor. 下载地址:点击打开链接 将下载完的CKEditor解压而且导入到项目中. 然后在页面引入CKEditor <script type="text/javasc ...
- [AngularJS] ui-router: Abstract States
ui-router has the powerful ability to define abstract states, or states that can't be navigated to, ...
- Tomcat安装、配置、优化及负载均衡详解
一.常见JavaWeb服务器 1.WebLogic:是BEA公司的产品.WebSphereAS:是IBM公司的产品.JBossAS:红帽公司的产品,可以自行了解 2.Tomcat服 ...
- 具体解释Android中AsyncTask的使用
在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式须要为每个任务创建一个新的线程,任务完毕后通过Handler实例向UI线程发送消息,完毕界面的更新 ...
- android143 360 短信电话拦截
package com.itheima.mobileguard.services; import java.lang.reflect.Method; import android.app.Servic ...