最近修改了一个紧急需求跟线程变量(ThreadLocal)有关,这是在项目中第二次使用线程变量了, 一次是为了在线程的上下文中传递值,这是一次是为了并发的效率。所以想对线程变量做一个小的总结,在google了一大堆之后发现这篇文章讲的很好,所以就决定将它翻译过来。
原文链接:
http://javapapers.com/core-java/threadlocal/
以下为译文:
线程变量
线程变量核心理念是:每条线程可以通过get和set方法访问它自己的,独立初始化的一份对象的拷贝。
目录
线程变量介绍
什么是线程安全
线程变量的使用场景
线程变量使用例子
线程变量在java API中的使用
线程变量与内存泄漏
线程变量介绍
每个线程需要一个独立的对象实例以至于在多线程并发的时候不会有并发冲突。每个实例对每个线程都是唯一的。这只不过是线程安全的一种实现。
线程变量有一个重要的特点就是它是全局的。它可在线程的任何地方被访问到。还要注意到它总是被声明为static和final.
什么是线程安全
线程是一个单一的线性的执行过程。当我们提到多线程的应用的时候是指多个线程的执
行的过程在执行相同的代码行。在这种情况下,有一定的几率一条线程会进入或者修改另
一条线程的数据。当我们的数据不能那样共享的情况下,我们需要将它作为线程安全的。
下面
是一些实现线程安全的不同方法。
重入锁
互斥
线程变量
原子操作
在上面的列表中,线程变量只是线程安全的一个技术选择。我们现在明白了线程变量的使用场景。
线程变量的使用场景
这里为情不自禁的来引用Joshua Bloch的原话:
每个线程真正的上下文,如用户id和事物id。非常有用,当线程退出时易于清理,没有
内存泄漏。
每个线程一个对象实例可以带来高性能。
在无法直接控制的回调函数中传递变量:有时候我们通过第三方的包来回调到我们自
己的包中代码。在这种场景下,由于第三方包的能力缺陷,你不能将你需要的参数传递给
你自己的回调函数中。对于这种罕见的场景,线程变量正好能发挥它的用武之地。
上面这些用我自己的话说就是:我们有一个对象不是线程安全的,但是我们希望安全的使用它。我们可以将这个对象放在synchronized块中以达到同步的目的。另一个选择就是使用线程安全,每个线程都持有一个独立的对象来达到线程安全的目的。
线程变量使用的例子
package com.javapapers;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadLocalExample {
private static final ThreadLocal formatter = new ThreadLocal() {
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date) {
return formatter.get().format(date);
}
}
在上面的实例代码中,get()方法是需要理解的关键点。它返回此线程局部变量的当前线程副本中的值,如果在当前线程中没有这个值,它首先通过initialValue方法去初始化这个值,然后返回。
javadoc的例子
下面的类为每条线程产生一个唯一的本地标识。这个线程id会在第一次调用ThreadId.get()方法的时候被赋值,并且在随后的调用中保持不变。
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal threadId =
new ThreadLocal() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
线程变量在java API中的使用
在JDK1.7中我们有一个新的类叫做ThreadLocalRandom。它可以用来为每一个并行执行的线程产生随机数,随机种子对每个线程来说都是唯一的。这是一个很酷的实现。
下面的代码就是线程变量在ThreadLocalRandom中的实现
private static final ThreadLocal localRandom =
new ThreadLocal() {
protected ThreadLocalRandom initialValue() {
return new ThreadLocalRandom();
}
};
使用ThreadLocalRandom的例子
package com.javapapers;
import java.util.concurrent.ThreadLocalRandom;
public class ThreadLocalRandomExample {
public static void main(String args[]) throws InterruptedException {
//tossing 3 coins
for (int i = 0; i < 3; i++) {
final Thread thread = new Thread() {
public void run() {
System.out.print(Thread.currentThread().getName() + ":");
// generating 3 random numbers - random for every thread
for (int j = 0; j < 3; j++) {
final int random = ThreadLocalRandom.current().nextInt(1, 3);
System.out.print(random + ",");
}
System.out.println();
}
};
thread.start();
thread.join();
}
}
}
线程变量与内存泄漏
线程变量不是魔鬼,它是一个非常有用的API。所有的一切都是建立在我们怎么使用它的基础上。我们需要学会在不同的场景下使用不同的工具。我们不能因为大炮打不了蚊子而 责怪大炮没有用。
网络上大量的关于线程变量导致内存泄漏的抱怨。这“基本上”是不可能的。
还是来引用Joshua Bloch的话:
“线程变量在本质上没有任何问题:它们不导致内存泄漏,它们是高效的,它们比那些非线程变量更加本地化(因为它们具有更好的隐蔽性)。它们可能被错误的使用,当然,这样的事情在其他编程工具上面也时常发生....”
为什么说基本上不会发生内存泄漏呢,在“self-referential structures”这种场景下还是会发生内存泄漏的,参考
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6254531
分享到:
相关推荐
Java中ThreadLocal的设计与使用.doc
详解java底层实现原理,ThreadLocal底层实现的数据结构,为什么不会导致内存泄露
java 简单的ThreadLocal示例
java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...
NULL 博文链接:https://justsee.iteye.com/blog/791919
计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,...
ThreadLocal保证一个类的实例变量在各个线程中都有一份单独的拷贝, 从而不会影响其他线程中的实例变量
主要介绍了java 中ThreadLocal 的正确用法的相关资料,需要的朋友可以参考下
主要介绍了java 中ThreadLocal实例分析的相关资料,需要的朋友可以参考下
java的ThreadLocal[整理].pdf
一篇文章我们来分析一个Java中ThreadLocal内存泄露的案例。分析问题的过程比结果更重要,理论结合实际才能彻底分析出内存泄漏的原因。
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。使用这个工具类可以很简洁地编写出优美的多线程程序。接下来通过本文给大家介绍Java中的ThreadLocal,需要的朋友可以参考下
Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal Java资料—详解ThreadLocal
主要介绍了彻底理解Java 中的ThreadLocal的相关资料,需要的朋友可以参考下
深入研究java.lang.ThreadLocal类。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是 threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。
主要介绍了快速了解Java中ThreadLocal类,介绍了ThreadLocal 是什么,ThreadLocal的作用,ThreadLocal 原理等相关内容,具有一定参考价值,需要的朋友可以了解下。
简单分析Java线程编程中ThreadLocal类的使用共4页.pdf.zip
NULL 博文链接:https://bijian1013.iteye.com/blog/2380233
主要介绍了java 中ThreadLocal本地线程和同步机制的比较的相关资料,需要的朋友可以参考下
什么是ThreadLocal?顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突...