- 浏览: 578298 次
- 性别:
- 来自: 苏州
文章分类
- 全部博客 (206)
- Flask (1)
- JavaScript (3)
- Core Java (41)
- XML (1)
- Oracle (11)
- 软件安装及环境配置 (0)
- 其它 (9)
- 面试/笔试 (5)
- 项目 (0)
- JDBC (11)
- Servlet (4)
- MySql (4)
- JNDI (0)
- Hibernate (11)
- Java模式和构架设计 (0)
- Web设计 (22)
- JSP (8)
- Struts (13)
- Tomcat (2)
- Marven (2)
- SVN (2)
- Swing/AWT (1)
- jQuery (2)
- ExtJS (8)
- Python (22)
- Flex (1)
- Django (7)
- 算法 (5)
- English (1)
- Twisted (1)
- Linux (3)
- Rails (1)
- SVG (3)
- PostgreSQL (1)
ThreadLocal的核心思想很简单:为每个独立的线程提供一个变量的副本。
Java提供的synchronized关键字使用了“同步锁”的机制来阻止线程的竞争访问,即“以时间换空间”。: " 10pt; FONT-SIZE:> ThreadLocal则使用了“拷贝副本”的方式,人人有份,你用你的,我用我的,大家互不影响,是“以空间换时间”。每个线程修改变量时,实际上修改的是变量的副本,不怕影响到其它线程。
为了加深对ThreadLocal的理解,下面我使用一个例子来演示ThreadLocal如何隔离线程间的变量访问和修改:
【1】SerialNum类
package example.thread.threadLocal;
public class SerialNum {
private static int nextSerialNum = 1;
@SuppressWarnings("unchecked")
private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
@SuppressWarnings("unchecked")
public static void set(Integer newSerial){
serialNum.set(newSerial);
}
}
public class SerialNum {
private static int nextSerialNum = 1;
@SuppressWarnings("unchecked")
private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
@SuppressWarnings("unchecked")
public static void set(Integer newSerial){
serialNum.set(newSerial);
}
}
【2】GetSerialNumThread
package example.thread.threadLocal;
public class GetSerialNumThread implements Runnable {
public static void main(String args[]) {
GetSerialNumThread serialNumGetter = new GetSerialNumThread();
Thread t1 = new Thread(serialNumGetter, "Thread A");
Thread t2 = new Thread(serialNumGetter, "Thread B");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
public void run() {
int mySerialNum = getSerialNum();
System.out.println("线程 " + Thread.currentThread().getName()
+ " 获取到的序列号是" + mySerialNum);
System.out.println("线程 " + Thread.currentThread().getName()
+ " 修改了序列号为" + (mySerialNum * 3));
setSerialNum(mySerialNum * 3);
System.out.println("线程 " + Thread.currentThread().getName()
+ " 再次获得的序列号是" + getSerialNum());
}
private int getSerialNum() {
return SerialNum.get();
}
private void setSerialNum(int newSerialNum) {
SerialNum.set(new Integer(newSerialNum));
}
}
public class GetSerialNumThread implements Runnable {
public static void main(String args[]) {
GetSerialNumThread serialNumGetter = new GetSerialNumThread();
Thread t1 = new Thread(serialNumGetter, "Thread A");
Thread t2 = new Thread(serialNumGetter, "Thread B");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
public void run() {
int mySerialNum = getSerialNum();
System.out.println("线程 " + Thread.currentThread().getName()
+ " 获取到的序列号是" + mySerialNum);
System.out.println("线程 " + Thread.currentThread().getName()
+ " 修改了序列号为" + (mySerialNum * 3));
setSerialNum(mySerialNum * 3);
System.out.println("线程 " + Thread.currentThread().getName()
+ " 再次获得的序列号是" + getSerialNum());
}
private int getSerialNum() {
return SerialNum.get();
}
private void setSerialNum(int newSerialNum) {
SerialNum.set(new Integer(newSerialNum));
}
}
运行的结果如下:
线程 Thread A 获取到的序列号是1
线程 Thread A 修改了序列号为3
线程 Thread A 再次获得的序列号是3
线程 Thread B 获取到的序列号是2
线程 Thread B 修改了序列号为6
线程 Thread B 再次获得的序列号是6
线程 Thread A 修改了序列号为3
线程 Thread A 再次获得的序列号是3
线程 Thread B 获取到的序列号是2
线程 Thread B 修改了序列号为6
线程 Thread B 再次获得的序列号是6
可见第一个线程在调用SerialNum.set(int)方法修改static变量时,其实修改的是它自己的副本,而不是修改本地变量,第二个线程在初始化的时候拿到的序列号是2而不是7。
为什么会这样呢?明明serialNum是静态变量啊?其实我们只需要看看ThreadLocal的内部构造就知道了:
A. ThreadLocal的get()方法:
/**
* Returns the value in the current thread's copy of this thread-local
* variable. Creates and initializes the copy if this is the first time
* the thread has called this method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
return (T)map.get(this);
// Maps are constructed lazily. if the map for this thread
// doesn't exist, create it, with this ThreadLocal and its
// initial value as its only entry.
T value = initialValue();
createMap(t, value);
return value;
}
* Returns the value in the current thread's copy of this thread-local
* variable. Creates and initializes the copy if this is the first time
* the thread has called this method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
return (T)map.get(this);
// Maps are constructed lazily. if the map for this thread
// doesn't exist, create it, with this ThreadLocal and its
// initial value as its only entry.
T value = initialValue();
createMap(t, value);
return value;
}
B. ThreadLocal的set()方法:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Many applications will have no need for
* this functionality, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current threads' copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
* Sets the current thread's copy of this thread-local variable
* to the specified value. Many applications will have no need for
* this functionality, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current threads' copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
可以看到ThreadLocal在内部维护了一个Map,将变量的值和线程绑定起来,get/set方法都是对该线程对应的value进行操作,所以不会影响到其它线程。
发表评论
-
线程的停止
2010-12-24 00:30 1139既然stop()是不被推荐的 ... -
JDK环境变量的配置
2010-12-19 11:03 965JDK环境变量的配置 (1)JAVA_HOME C:\Pro ... -
自定义异常
2010-12-10 12:09 1200内置异常不可能始终足以捕获所有错误,因此需要用户自定义的异常类 ... -
编写异常的规范
2010-12-10 11:35 1159错误的编码: OutputStreamWriter out ... -
内部类
2010-12-06 16:51 1127内部类详解 1、定义 一个类的定义放在另一个类的内部,这个 ... -
抽象类和接口的区别
2010-12-06 16:47 1054含有abstract修饰符的class 即为抽象类,abstr ... -
人工抛出异常
2010-12-06 16:35 2090Java异常类对象除在程序执行过程中出现异常时由系统自动生成并 ... -
Java异常处理机制
2010-12-06 16:30 10511.Java程序的执行过程中如出现异常,会自动生成一个异常类对 ... -
Java的垃圾回收原理与机制
2010-12-06 16:12 1157JAVA中的对象是在堆上分配,而在堆上分配存储空间的方式是昂贵 ... -
Comparable和Comparator接口
2010-12-06 15:13 1700当需要排序的集合或数组不是单纯的数字型时,通常可以使用Comp ... -
手工打包JAR
2010-12-06 12:57 22291.把准备打包的.java文件集中到一个目录中例如c:\sou ... -
Java集合类
2010-12-03 14:26 1291Collection接口 Collection是 ... -
Java Socket 初步详解
2010-11-08 09:05 1068网络编程的基本模型就 ... -
Java中newString(abc)创建几个对象的解释
2010-11-02 10:04 1889String str=new String("abc ... -
Java日期处理
2010-10-19 17:17 14161.有关日期时间的类 1.java.util.Date ... -
线程同步
2010-10-17 21:17 1079一个方法被synchronized修饰:当程序执行此方法时,当 ... -
线程的状态及生命周期
2010-10-17 20:29 1508线程共有6种状态;在某一时刻只能是这6种状态之一。这些状态由T ... -
sleep()、wait()、yield()、join()方法 浅析
2010-10-17 18:54 1093线程退出最好自己实现,在运行状态中一直检验一个状态,如果这 ... -
RandomAccessFile类的应用
2010-10-17 10:39 1770文件存取通常是顺序的,每在文件中存取一次,文件的读 ... -
利用Externalizable接口实现对象的自定义序列化
2010-10-17 10:12 1302SerializedUser.java import jav ...
相关推荐
【JAVA ThreadLocal类深入】 Java中的ThreadLocal类是一种线程绑定机制,用于在多线程环境中为每个线程提供独立的变量副本,避免了线程间的数据共享带来的并发访问问题。ThreadLocal并不是一个线程对象,而是线程...
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...
### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...
Java中的ThreadLocal类是一个强大的工具,它允许程序员创建线程局部变量。这意味着每个线程都有其自己独立的、不可见的变量副本,从而避免了线程间的数据共享问题,简化了多线程环境下的编程复杂性。ThreadLocal并不...
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
Java ThreadLocal类应用实战案例分析 Java ThreadLocal类是Java语言中的一种线程局部变量机制,允许每个线程都拥有自己的变量副本,从而避免了多线程之间的变量冲突。在本文中,我们将通过实战案例分析Java ...
Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327
Java并发编程中的ThreadLocal类是一个非常重要的工具,它允许我们在多线程环境下为每个线程维护独立的变量副本,从而避免了线程间的数据共享和同步问题。ThreadLocal并不是一个线程,而是一个线程局部变量的容器。...
ThreadLocal类位于`java.lang`包下,其设计目标是为每个线程提供一种便捷的方式,来存储与该线程相关的数据。每个ThreadLocal实例都有一个与之关联的线程局部变量,每个线程都可以通过`get()`方法获取属于自己的变量...
ThreadLocal类的核心在于`initialValue()`方法和`get()`方法。`initialValue()`是线程首次访问ThreadLocal变量时调用的,返回的是默认值。`get()`方法则会查找当前线程的ThreadLocalMap,如果没有找到对应的值,就...
在Java多线程编程中,ThreadLocal类是一个非常重要的工具,它主要用于解决线程安全问题。ThreadLocal提供了一个线程局部变量,也就是说,每个线程都有自己的独立副本,互不影响。这种机制使得线程间的数据隔离得以...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
ThreadLocal 是 Java 中一个非常重要的类,它为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal 并不是一个 Thread,而是 Thread 的局部变量,它为每个使用该变量的线程提供独立的变量副本,所以每一个...
ThreadLocal 并不是 Java 的新发明,而是一个变相地通过 ThreadLocal 的类提供支持的解决方案。 ThreadLocal 类中的方法包括: * void set(T value):将此线程局部变量的当前线程副本中的值设置为指定值。 * void ...
在ThreadLocal类的内部,它利用了一个HashMap来存储每个线程的变量副本。在这个Map中,键(Key)是线程对象本身,而值(Value)则是线程的变量副本。由于线程对象作为键是唯一的,因此每个线程都有其对应的独立变量...
ThreadLocal 是 Java 中的一个类,它提供了一个简单的方式来在每个线程中存储变量,并且能够确保这些变量之间不受影响。下面是对 ThreadLocal 的简单理解。 一、背景 最近有人问我 ThreadLocal 是如何做到在每个...
创建ThreadLocal变量非常简单,只需实例化ThreadLocal类即可,如下所示: ```java private ThreadLocal<String> myThreadLocal = new ThreadLocal(); ``` 这里的`<String>`是可选的,用于指定ThreadLocal变量所...
DbUTils中用ThreadLocal类
这篇文档深入探讨了Java中的ThreadLocal类,这是一个在多线程编程中非常关键的工具。ThreadLocal提供了线程局部变量,也就是说,每个线程都有自己的独立副本,互不影响。它的工作原理是通过内部的哈希表存储每个线程...