在java中,如果一个变量需要被多个线程访问,可以使用volatile来声明它为“易变的”。而假如一个变量要被持有它的某个线程独享,在java中,它可以使用java.lang.ThreadLocal类来实现线程本地存储的功能。这样,数据便只在同一个线程内可见和共享,因此,即便不同步也能保证线程之间不出现数据争用。
ThreadLocal使得各线程能够保持各自独立的一个对象,通过ThreadLocal.set()来设置对象的值,保存在每个线程自己都有的一个map对象当中,每个ThreadLocal对象会有一个线程范围内唯一hashcode作为key,ThreadLocal.get()内部通过这个key从map中取值,因此取出来的是各自自己线程中的对象,ThreadLocal实例事实上只是作为map的key来使用的。
一个ThreadLocal的例子:
- package com.threadlocal.test;
- /**
- * @Author: chenkangxian
- *
- * @Annotation:
- *
- * @Date:2012-4-20
- *
- */
- public class test {
- class ConcurrentCount extends Thread{
- ThreadLocal<Integer> count ;
- public ConcurrentCount(ThreadLocal<Integer> count){
- this.count = count;
- }
- @Override
- public void run() {
- for(int i = 0; i < 10; i ++){
- if(count.get() != null){
- count.set(count.get() + 1);
- }else{
- count.set(0);
- }
- System.out.println("Thread: " + this.currentThread().getName() + ", count: " + count.get());
- }
- return ;
- }
- }
- /**
- * Author: chenkangxian
- *
- * Last Modification Time: 2012-4-20
- *
- * @param args
- */
- public static void main(String[] args) {
- //所有线程均使用该变量,但是却不存在线程安全问题
- ThreadLocal<Integer> count = new ThreadLocal<Integer>();
- test test = new test();
- ConcurrentCount count1 = test.new ConcurrentCount(count);
- ConcurrentCount count2 = test.new ConcurrentCount(count);
- ConcurrentCount count3 = test.new ConcurrentCount(count);
- ConcurrentCount count4 = test.new ConcurrentCount(count);
- count1.start();
- count2.start();
- count3.start();
- count4.start();
- }
- }
ThreadLocal使用归纳有两点:
1.每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2.将一个共用的ThreadLocal实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象。
ThreadLocal实现的源代码:
- /*
- * @(#)ThreadLocal.java 1.42 06/06/23
- *
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang;
- import java.lang.ref.*;
- import java.util.concurrent.atomic.AtomicInteger;
- new ThreadLocal < Integer > () {
- public class ThreadLocal<T> {
- private final int threadLocalHashCode = nextHashCode();
- /**
- * The next hash code to be given out. Updated atomically. Starts at
- * zero.
- */
- private static AtomicInteger nextHashCode =
- new AtomicInteger();
- /**
- * The difference between successively generated hash codes - turns
- * implicit sequential thread-local IDs into near-optimally spread
- * multiplicative hash values for power-of-two-sized tables.
- */
- private static final int HASH_INCREMENT = 0x61c88647;
- /**
- * Returns the next hash code.
- */
- private static int nextHashCode() {
- return nextHashCode.getAndAdd(HASH_INCREMENT);
- }
- * @return the initial value for this thread-local
- */
- protected T initialValue() {
- return null;
- }
- /**
- * Creates a thread local variable.
- */
- public ThreadLocal() {
- }
- public T get() {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- ThreadLocalMap.Entry e = map.getEntry(this);
- if (e != null)
- return (T)e.value;
- }
- return setInitialValue();
- }
- private T setInitialValue() {
- T value = initialValue();
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- return value;
- }
- public void set(T value) {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- }
- public void remove() {
- ThreadLocalMap m = getMap(Thread.currentThread());
- if (m != null