- 浏览: 167055 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
mengyue0477:
最后还不忘吐槽一下 哈哈 太逗了
spring容器的懒加载lazy-init设置 -
comet0515:
不是maven工程能不能用checkstyle插件?job是一 ...
jenkins 配置checkstyle -
xfxlch:
http://docs.spring.io/spring-bo ...
NoteBook -
With_Me_Forever:
太浅了。我最近也在看着方面的资料,一起进步把。
互联网金融定义 -
xfxlch:
在http://r.m.baidu.com/6pmxgig
NoteBook
Java线程:深入ThreadLocal
ThreadLocal与线程成员变量还有区别,ThreadLocal该类提供了线程局部变量。这个局部变量与一般的成员变量不一样,ThreadLocal的变量在被多个线程使用时候,每个线程只能拿到该变量的一个副本,这是Java API中的描述,通过阅读API源码,发现并非副本,副本什么概念?克隆品? 或者是别的样子,太模糊。
准确的说,应该是ThreadLocal类型的变量内部的注册表(Map<Thread,T>)发生了变化,但ThreadLocal类型的变量本身的确是一个,这才是本质!
下面就做个例子:
一、标准例子
定义了MyThreadLocal类,创建它的一个对象tlt,分别给四个线程使用,结果四个线程tlt变量并没有出现共用现象,二是各用各的,这说明,四个线程使用的是tlt的副本(克隆品)。
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}
/**
* 测试线程
*
* @author leizhimin 2010-1-5 10:39:18
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();
public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + tlt.getNextNum());
}
}
}
/**
* ThreadLocal测试
*
* @author leizhimin 2010-1-5 10:43:48
*/
public class Test {
public static void main(String[] args) {
MyThreadLocal tlt = new MyThreadLocal();
Thread t1 = new TestThread(tlt);
Thread t2 = new TestThread(tlt);
Thread t3 = new TestThread(tlt);
Thread t4 = new TestThread(tlt);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
可以看出,三个线程各自独立编号,互不影响:
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 3
Thread-1 3
Thread-2 1
Thread-3 1
Thread-2 2
Thread-3 2
Thread-2 3
Thread-3 3
Process finished with exit code 0
tlt对象是一个,废话tl对象也是一个,因为组合关系是一对一的。但是tl对象内部的Map随着线程的增多,会创建很多Integer对象。只是Integer和int已经通用了。所以感觉不到Integer的对象属性。
二、不用ThreadLocal
假如不用ThreadLocal,只需要将MyThreadLocal类重新定义为:
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
private Integer t1 = 0;
public Integer getNextNum(){
return t1=t1+1;
}
// //定义了一个ThreadLocal变量,用来保存int或Integer数据
// private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
// @Override
// protected Integer initialValue() {
// return 0;
// }
// };
//
// public Integer getNextNum() {
// //将tl的值获取后加1,并更新设置t1的值
// tl.set(tl.get() + 1);
// return tl.get();
// }
}
然后运行测试:
Thread-2 1
Thread-2 2
Thread-1 4
Thread-1 6
Thread-3 3
Thread-3 9
Thread-3 10
Thread-1 8
Thread-0 7
Thread-0 11
Thread-0 12
Thread-2 5
Process finished with exit code 0
从这里可以看出,四个线程共享了tlt变量,结果每个线程都直接修改tlt的属性。
三、自己实现个ThreadLocal
package com.lavasoft.test2;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private com.lavasoft.test2.ThreadLocal<Integer> tl = new com.lavasoft.test2.ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}
class ThreadLocal<T> {
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());
public ThreadLocal() {
}
protected T initialValue() {
return null;
}
public T get() {
Thread t = Thread.currentThread();
T obj = map.get(t);
if (obj == null && !map.containsKey(t)) {
obj = initialValue();
map.put(t, obj);
}
return obj;
}
public void set(T value) {
map.put(Thread.currentThread(), value);
}
public void remove() {
map.remove(Thread.currentThread());
}
}
运行测试:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-2 1
Thread-2 2
Thread-3 1
Thread-2 3
Thread-3 2
Thread-1 1
Thread-3 3
Thread-1 2
Thread-1 3
Process finished with exit code 0
很意外,这个山寨版的ThreadLocal也同样运行很好,实现了JavaAPI中ThreadLocal的功能。
四、透过现象看本质
其实从程序角度看,tlt变量的确是一个,毫无疑问的。但是为什么打印出来的数字就互不影响呢?
是因为使用了Integer吗?-----不是。
原因是:protected T initialValue()和get(),因为每个线程在调用get()时候,发现Map中不存在就创建。调用它的时候,就创建了一个新变量,类型为T。每次都新建,当然各用个的互不影响了。
为了看清本质,将Integer换掉,重写部分类:
package com.lavasoft.test2;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
// private ThreadLocal<Bean> tl = new ThreadLocal<Bean>() {
private com.lavasoft.test2.ThreadLocal<Bean> tl = new com.lavasoft.test2.ThreadLocal<Bean>() {
@Override
protected Bean initialValue() {
return new Bean();
}
};
@Override
public String toString() {
return "MyThreadLocal{" +
"tl=" + tl +
'}';
}
public Bean getBean() {
return tl.get();
}
}
class ThreadLocal<T> {
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());
public ThreadLocal() {
}
protected T initialValue() {
return null;
}
public T get() {
Thread t = Thread.currentThread();
T obj = map.get(t);
if (obj == null && !map.containsKey(t)) {
obj = initialValue();
map.put(t, obj);
}
return obj;
}
public void set(T value) {
map.put(Thread.currentThread(), value);
}
public void remove() {
map.remove(Thread.currentThread());
}
}
package com.lavasoft.test2;
/**
* 测试Bean
*
* @author leizhimin 2010-1-5 14:18:26
*/
public class Bean {
private String id = "0";
private String name = "none";
public Bean() {
}
public Bean(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String showinfo() {
return "Bean{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
package com.lavasoft.test2;
/**
* 测试线程
*
* @author leizhimin 2010-1-5 10:39:18
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();
public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}
@Override
public void run() {
System.out.println(">>>>>:" + tlt);
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" +tlt.getBean()+"\t"+tlt.getBean().showinfo());
}
}
}
然后运行测试:
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Process finished with exit code 0
从打印结果很清楚的看到,MyThreadLocal的tlt对象的确是一个,tlt对象里的ThreadLocal的tl对象也是一个,但是,将t1t给每个线程用的时候,线程会重新创建Bean对象加入到ThreadLocal的Map中去使用。
ThreadLocal与线程成员变量还有区别,ThreadLocal该类提供了线程局部变量。这个局部变量与一般的成员变量不一样,ThreadLocal的变量在被多个线程使用时候,每个线程只能拿到该变量的一个副本,这是Java API中的描述,通过阅读API源码,发现并非副本,副本什么概念?克隆品? 或者是别的样子,太模糊。
准确的说,应该是ThreadLocal类型的变量内部的注册表(Map<Thread,T>)发生了变化,但ThreadLocal类型的变量本身的确是一个,这才是本质!
下面就做个例子:
一、标准例子
定义了MyThreadLocal类,创建它的一个对象tlt,分别给四个线程使用,结果四个线程tlt变量并没有出现共用现象,二是各用各的,这说明,四个线程使用的是tlt的副本(克隆品)。
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}
/**
* 测试线程
*
* @author leizhimin 2010-1-5 10:39:18
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();
public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + tlt.getNextNum());
}
}
}
/**
* ThreadLocal测试
*
* @author leizhimin 2010-1-5 10:43:48
*/
public class Test {
public static void main(String[] args) {
MyThreadLocal tlt = new MyThreadLocal();
Thread t1 = new TestThread(tlt);
Thread t2 = new TestThread(tlt);
Thread t3 = new TestThread(tlt);
Thread t4 = new TestThread(tlt);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
可以看出,三个线程各自独立编号,互不影响:
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 3
Thread-1 3
Thread-2 1
Thread-3 1
Thread-2 2
Thread-3 2
Thread-2 3
Thread-3 3
Process finished with exit code 0
tlt对象是一个,废话tl对象也是一个,因为组合关系是一对一的。但是tl对象内部的Map随着线程的增多,会创建很多Integer对象。只是Integer和int已经通用了。所以感觉不到Integer的对象属性。
二、不用ThreadLocal
假如不用ThreadLocal,只需要将MyThreadLocal类重新定义为:
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
private Integer t1 = 0;
public Integer getNextNum(){
return t1=t1+1;
}
// //定义了一个ThreadLocal变量,用来保存int或Integer数据
// private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
// @Override
// protected Integer initialValue() {
// return 0;
// }
// };
//
// public Integer getNextNum() {
// //将tl的值获取后加1,并更新设置t1的值
// tl.set(tl.get() + 1);
// return tl.get();
// }
}
然后运行测试:
Thread-2 1
Thread-2 2
Thread-1 4
Thread-1 6
Thread-3 3
Thread-3 9
Thread-3 10
Thread-1 8
Thread-0 7
Thread-0 11
Thread-0 12
Thread-2 5
Process finished with exit code 0
从这里可以看出,四个线程共享了tlt变量,结果每个线程都直接修改tlt的属性。
三、自己实现个ThreadLocal
package com.lavasoft.test2;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private com.lavasoft.test2.ThreadLocal<Integer> tl = new com.lavasoft.test2.ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}
class ThreadLocal<T> {
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());
public ThreadLocal() {
}
protected T initialValue() {
return null;
}
public T get() {
Thread t = Thread.currentThread();
T obj = map.get(t);
if (obj == null && !map.containsKey(t)) {
obj = initialValue();
map.put(t, obj);
}
return obj;
}
public void set(T value) {
map.put(Thread.currentThread(), value);
}
public void remove() {
map.remove(Thread.currentThread());
}
}
运行测试:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-2 1
Thread-2 2
Thread-3 1
Thread-2 3
Thread-3 2
Thread-1 1
Thread-3 3
Thread-1 2
Thread-1 3
Process finished with exit code 0
很意外,这个山寨版的ThreadLocal也同样运行很好,实现了JavaAPI中ThreadLocal的功能。
四、透过现象看本质
其实从程序角度看,tlt变量的确是一个,毫无疑问的。但是为什么打印出来的数字就互不影响呢?
是因为使用了Integer吗?-----不是。
原因是:protected T initialValue()和get(),因为每个线程在调用get()时候,发现Map中不存在就创建。调用它的时候,就创建了一个新变量,类型为T。每次都新建,当然各用个的互不影响了。
为了看清本质,将Integer换掉,重写部分类:
package com.lavasoft.test2;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 使用了ThreadLocal的类
*
* @author leizhimin 2010-1-5 10:35:27
*/
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
// private ThreadLocal<Bean> tl = new ThreadLocal<Bean>() {
private com.lavasoft.test2.ThreadLocal<Bean> tl = new com.lavasoft.test2.ThreadLocal<Bean>() {
@Override
protected Bean initialValue() {
return new Bean();
}
};
@Override
public String toString() {
return "MyThreadLocal{" +
"tl=" + tl +
'}';
}
public Bean getBean() {
return tl.get();
}
}
class ThreadLocal<T> {
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>());
public ThreadLocal() {
}
protected T initialValue() {
return null;
}
public T get() {
Thread t = Thread.currentThread();
T obj = map.get(t);
if (obj == null && !map.containsKey(t)) {
obj = initialValue();
map.put(t, obj);
}
return obj;
}
public void set(T value) {
map.put(Thread.currentThread(), value);
}
public void remove() {
map.remove(Thread.currentThread());
}
}
package com.lavasoft.test2;
/**
* 测试Bean
*
* @author leizhimin 2010-1-5 14:18:26
*/
public class Bean {
private String id = "0";
private String name = "none";
public Bean() {
}
public Bean(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String showinfo() {
return "Bean{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
package com.lavasoft.test2;
/**
* 测试线程
*
* @author leizhimin 2010-1-5 10:39:18
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();
public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}
@Override
public void run() {
System.out.println(">>>>>:" + tlt);
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" +tlt.getBean()+"\t"+tlt.getBean().showinfo());
}
}
}
然后运行测试:
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
>>>>>:MyThreadLocal{tl=com.lavasoft.test2.MyThreadLocal$1@1de3f2d}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-3 com.lavasoft.test2.Bean@186db54 Bean{id='0', name='none'}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-0 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Thread-1 com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'}
Process finished with exit code 0
从打印结果很清楚的看到,MyThreadLocal的tlt对象的确是一个,tlt对象里的ThreadLocal的tl对象也是一个,但是,将t1t给每个线程用的时候,线程会重新创建Bean对象加入到ThreadLocal的Map中去使用。
发表评论
-
eclipse project .setting
2016-08-24 11:30 601有一个文件在.setting的目录下面: 文件名:org.ec ... -
jar命令工具
2016-01-23 20:29 687背景: 今天介绍两个jar的命令工具,对我个人来说,还是比较好 ... -
Java的按值传递
2016-01-23 19:30 555问题: 最近在看Mar ... -
Mac OS 安装java 开发环境
2016-01-03 13:00 1771我的机器是: 1. jdk1.7下载安装 jdk7:h ... -
记一次Java Rest Service Hang住的经历
2015-12-28 20:08 2698背景: 在前后端分开开发的过程中,前段的页面要调用后台Java ... -
一个String字符串的问题2
2015-12-14 14:22 608背景: 今天遇到个问题: String str = & ... -
我读重构这本书
2015-12-01 22:30 0第一点:关注变量命名。好的变量名能让读者更快更好的理解程序到底 ... -
系统log的编写
2015-11-16 09:41 0log很关键,一定要记录好对追踪问题有帮助的日志。 -
CAS 授权问题
2015-11-16 09:40 0CAS 授权问题 -
Caused by: java.lang.UnsupportedOperationException 解决方案
2015-10-21 22:09 4061背景: 今天在跑一个UnitTest,跑的过程中想在list ... -
LogBack 框架里log-access的使用
2015-10-18 16:05 7096背景: 想通过配置log-access来实现直接使用浏览器来访 ... -
how to fix "org.hamcrest.CoreMatchers.containsString cannot be resolved"
2015-09-23 23:12 3025背景: 山姆大叔比较喜欢用一些新的技术和新的特性,最近在jun ... -
java 打印金字塔
2015-08-24 00:53 780背景: 一个同事,面试应聘者喜欢用学校里学过的一个书本或者课后 ... -
纯jsp servlet 实现 upload file功能
2015-08-17 20:35 738本篇主要是简单的实现jsp servlet 的上传文件的功能, ... -
dos 命令窗口執行java 命令,帶包路徑
2015-07-26 12:16 532記錄一下,是為了自己下次再run java命令的時候,可以很快 ... -
tomcat 远程调试
2015-07-23 18:41 488背景: 我们在项目开发过程中,很多时候会遇到这样的情况:项目在 ... -
使用android studio 来开发hello world app的时候,遇到的一些坑。
2015-07-13 01:38 2159使用android studio 来开发h ... -
Hibernate Interceptor(拦截器)
2015-04-28 20:30 2416需求: 对所有操作数据库的事件,添加audit log, 此l ... -
eclipse 加入tomcat 包
2015-03-24 01:09 429... -
Transforming XML with XSLT
2014-10-11 19:14 523public static void catalog() ...
相关推荐
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...
在 `LeakingServlet` 的 `doGet` 方法中,如果 `ThreadLocal` 没有设置值,那么会创建一个新的 `MyCounter` 并设置到 `ThreadLocal` 中。关键在于,一旦 `MyCounter` 被设置到 `ThreadLocal`,那么它将与当前线程...
Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...
### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本概念 `ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每...
ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...
ThreadLocal是Java编程语言中的一个线程局部变量类,它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地改变自己的副本,而不会影响其他线程所对应的副本。这个特性在多线程环境下处理并发问题时非常...
### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...
ThreadLocal 整理 ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本。这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都...
private static final ThreadLocal<Connection> connectionHolder = new ThreadLocal(); public static void setConnection(Connection conn) { connectionHolder.set(conn); } public static Connection get...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...
本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并提供全局访问点的设计模式。在Java中,通常通过私有构造函数、静态工厂方法或...
**线程局部变量(ThreadLocal)是Java编程中一个非常重要的概念,主要用于在多线程环境中为每个线程提供独立的变量副本。ThreadLocal不是一种数据结构,而是一种解决线程间共享数据的方式,它提供了线程安全的局部...
在Java编程中,ThreadLocal是线程局部变量的类,它提供了一种在多线程环境中为每个线程创建和维护独立副本的机制。ThreadLocal主要用于解决线程间的数据隔离问题,确保各线程拥有自己的变量副本,避免了数据共享带来...
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
这个压缩包 "Quartz-ThreadLocal.rar" 内含的学习资源很可能是关于如何在 Quartz 调度器中结合使用 ThreadLocal 的示例。 Quartz 的核心功能包括: 1. **作业与触发器**:在 Quartz 中,任务被称为“作业”(Job)...
**标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,用于为每个线程提供独立的变量副本。理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ...