原帖地址:http://javapapers.com/core-java/threadlocal/
尝试翻译,欢迎批评指正。
原文地址:http://javapapers.com/core-java/threadlocal/
ThreadLocal的核心概念是没一个线程可以通过get或者set方法访问它自己的、独立初始化的变量的副本。
1. ThreadLocal介绍
为了在多线程环境下不出现任何的冲突,我们希望能否分离一个类的多个实例。对于每一个线程来说,没一个实例都是唯一的。这不过是实现线程安全的一个方式。
线程安全的另外的重要的一点是能够全局访问。可以在线程内部的任何地方进行访问。记住:应该声明成static和final的。
2. 什么是线程安全
线程是进程的一条单独的线。当我们提到多线程应用的时候,我们的意思是一个进程的多个线程访问同一行代码。在这个情况下,存在一个线程访问或者修改另一个线程的数据的可能性。当数据不允许这样共享的时候,我们应该做成线程安全的。实现线程安全的方式有下面几种:
· 重入
·互斥(同步机制)
·ThreadLocal
·原子操作
3. 使用ThreadLocal
(引用Joshua Bloch的一段话,巨抽象,我没看懂,......)
我们有一个非线程安全的变量,我们想把它变成线程安全的,可以考虑同步机制把对象封闭到同步块中。另外的方式是使用ThreadLocal,为每一个线程持有单独的对象使得变得安全。
4. ThreadLocal的例子
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()方法。他返回的当前线程的ThreadLocal变量的副本。如果当前线程的这个变量还没有值,则通过调用initalValue方法返回第一次初始化的值。
JavaDoc中的例子
下面的例子为每一个线程生成一个唯一的标识符。第一次调用get方法的时候指定一个线程的id,并且在随后的调用中保持不变。
port 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(); } } |
5. Java API中ThreadLocal 的使用
在JDK1.7中,我们有一个叫做ThreadLocalRandom的新类。它用于为并行的线程生成随机数,每一个线程是随机数的种子都是唯一的。这是一个非常酷的功能。
下面的代码是上边的类实现ThreadLocal 的代码:
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(); } } } |
6. ThreadLocal和内存泄露
ThreadLocal不是一个魔鬼,而是一个优秀的、实用的API。完全取决于我们怎么样去使用。我们应该学会在正确的场合使用合适的工具。我们不能使用大炮打蚊子,但是也不能谴责大炮。
PDF文件下载: