`

Threadlocal

    博客分类:
  • java
阅读更多
ThreadLocal的实现原理,及使用实例,解决spring,hibernate非web项目下的懒加载 no session or session was closed(1)! 收藏
JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的局部变量独立问题...

查看API我们可以查看ThreadLocal的定义与方法:

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

例如,以下类生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。

构造方法摘要
ThreadLocal()
          创建一个线程本地变量。
  方法摘要
T get()
          返回此线程局部变量的当前线程副本中的值。
protected  T initialValue()
          返回此线程局部变量的当前线程的“初始值”。
void remove()
          移除此线程局部变量当前线程的值。
void set(T value)
          将此线程局部变量的当前线程副本中的值设置为指定值。


remove()

移除此线程局部变量当前线程的值,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

initialValue()

返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。如果泛型对象是Integer,可以定义内部内,重写initialValue() 返回0等Integer类型的数据!

ThreadLocal并非一个所谓的 "local thread (本地线程)",而是处理线程中的局部变量的.其可以理解为:"local thread variable(线程局部变量)"!

线程局部变量已经有很多语言使用了,并非是Java独创...很多语言(如IBM IBM XL FORTRAN)在语法层面就提供线程局部变量。

ThreadLocal的具体实现原理大致如下:

view plaincopy to clipboardprint?
package cn.vicky;  
 
import java.util.Collections;  
import java.util.HashMap;  
import java.util.Map;  
 
public class RealizeThreadLocal {  
 
    private Map<String, Object> map = Collections.synchronizedMap(new HashMap<String, Object>());  
 
    public void set(Object value) {  
        map.put(Thread.currentThread().getName(), value);   
    }  
 
    public Object get() {  
        String threadName = Thread.currentThread().getName();  
        Object o = map.get(threadName);  
        if (o == null && !map.containsKey(threadName)) {  
            o = initialValue();  
            map.put(threadName, o);  
        }  
        return o;  
    }  
 
    public void remove() {  
        map.remove(Thread.currentThread().getName());  
    }  
 
    public Object initialValue() {  
        return null;  
    }  
 

package cn.vicky;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class RealizeThreadLocal {

private Map<String, Object> map = Collections.synchronizedMap(new HashMap<String, Object>());

public void set(Object value) {
map.put(Thread.currentThread().getName(), value);
}

public Object get() {
String threadName = Thread.currentThread().getName();
Object o = map.get(threadName);
if (o == null && !map.containsKey(threadName)) {
o = initialValue();
map.put(threadName, o);
}
return o;
}

public void remove() {
map.remove(Thread.currentThread().getName());
}

public Object initialValue() {
return null;
}

}


在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。其实现原理大致如下:

view plaincopy to clipboardprint?
package cn.vicky;  
 
import java.util.Collections;  
import java.util.HashMap;  
import java.util.Map;  
 
public class RealizeThreadLocal2<T> {  
 
    private Map<Long, T> map = Collections.synchronizedMap(new HashMap<Long, T>());  
 
    public void set(T value) {  
        map.put(Thread.currentThread().getId(), value);  
    }  
 
    public T get() {  
        long threadID = Thread.currentThread().getId();  
        T o = map.get(threadID);  
        if (o == null && !map.containsKey(threadID)) {  
            o = initialValue();  
            map.put(threadID, o);  
        }  
        return o;  
    }  
 
    public void remove() {  
        map.remove(Thread.currentThread().getName());  
    }  
 
    public T initialValue() {  
        return null;  
    }  

package cn.vicky;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class RealizeThreadLocal2<T> {

private Map<Long, T> map = Collections.synchronizedMap(new HashMap<Long, T>());

public void set(T value) {
map.put(Thread.currentThread().getId(), value);
}

public T get() {
long threadID = Thread.currentThread().getId();
T o = map.get(threadID);
if (o == null && !map.containsKey(threadID)) {
o = initialValue();
map.put(threadID, o);
}
return o;
}

public void remove() {
map.remove(Thread.currentThread().getName());
}

public T initialValue() {
return null;
}
}


如何使用:

view plaincopy to clipboardprint?
package cn.vicky;  
 
public class SequenceNumber {  
 
    // 通过匿名内部类覆盖RealizeThreadLocal2的initialValue()方法,根据泛型类型指定对应初始值  
    private static RealizeThreadLocal2<Integer> seqNum = new RealizeThreadLocal2<Integer>() {  
        @Override 
        public Integer initialValue() {  
            return 0;  
        }  
    };  
 
    // 获取下一个序列值  
    public int getNextNum() {  
        seqNum.set(seqNum.get() + 1);  
        return seqNum.get();  
    }  
 
    public static void main(String[] args) {  
        SequenceNumber sn = new SequenceNumber();  
        // 3个线程共享sn,各自产生序列号  
        TestThread tt1 = new TestThread(sn);  
        TestThread tt2 = new TestThread(sn);  
        TestThread tt3 = new TestThread(sn);  
        Thread t1 = new Thread(tt1);  
        Thread t2 = new Thread(tt2);  
        Thread t3 = new Thread(tt3);  
        t1.start();  
        t2.start();  
        t3.start();  
    }  

package cn.vicky;

public class SequenceNumber {

// 通过匿名内部类覆盖RealizeThreadLocal2的initialValue()方法,根据泛型类型指定对应初始值
private static RealizeThreadLocal2<Integer> seqNum = new RealizeThreadLocal2<Integer>() {
@Override
public Integer initialValue() {
return 0;
}
};

// 获取下一个序列值
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}

public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
// 3个线程共享sn,各自产生序列号
TestThread tt1 = new TestThread(sn);
TestThread tt2 = new TestThread(sn);
TestThread tt3 = new TestThread(sn);
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt2);
Thread t3 = new Thread(tt3);
t1.start();
t2.start();
t3.start();
}
}


view plaincopy to clipboardprint?
package cn.vicky;  
 
public class TestThread implements Runnable {  
    private SequenceNumber sn;  
 
    public TestThread(SequenceNumber sn) {  
        this.sn = sn;  
    }  
 
    public void run() {  
        // 每个线程打出3个序列值  
        for (int i = 0; i < 3; i++) {  
            System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]");  
        }  
    }  

package cn.vicky;

public class TestThread implements Runnable {
private SequenceNumber sn;

public TestThread(SequenceNumber sn) {
this.sn = sn;
}

public void run() {
// 每个线程打出3个序列值
for (int i = 0; i < 3; i++) {
System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]");
}
}
}


打印:

thread[Thread-0] sn[1]
thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]

TestThread tt1 = new TestThread(sn);
TestThread tt2 = new TestThread(sn);
TestThread tt3 = new TestThread(sn);

输出的结果信息,我们发现每个线程所产生的序号虽然都共享同一个SequenceNumber (sn) 实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本!



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/eclipser1987/archive/2010/01/29/5268084.aspx
分享到:
评论

相关推荐

    ThreadLocal应用示例及理解

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...

    ThreadLocal

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...

    ThreadLocal 内存泄露的实例分析1

    在 `LeakingServlet` 的 `doGet` 方法中,如果 `ThreadLocal` 没有设置值,那么会创建一个新的 `MyCounter` 并设置到 `ThreadLocal` 中。关键在于,一旦 `MyCounter` 被设置到 `ThreadLocal`,那么它将与当前线程...

    java事务 - threadlocal

    Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...

    正确理解ThreadLocal.pdf

    ### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本概念 `ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每...

    ThreadLocal的几种误区

    ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...

    threadLocal

    ThreadLocal是Java编程语言中的一个线程局部变量类,它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地改变自己的副本,而不会影响其他线程所对应的副本。这个特性在多线程环境下处理并发问题时非常...

    java中ThreadLocal详解

    ### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...

    ThreadLocal整理.docx

    ThreadLocal 整理 ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本。这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都...

    事务的封装和Threadlocal实例

    private static final ThreadLocal&lt;Connection&gt; connectionHolder = new ThreadLocal(); public static void setConnection(Connection conn) { connectionHolder.set(conn); } public static Connection get...

    java 简单的ThreadLocal示例

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...

    设计模式及ThreadLocal资料

    本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并提供全局访问点的设计模式。在Java中,通常通过私有构造函数、静态工厂方法或...

    ThreadLocal原理及在多层架构中的应用

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的概念,主要用于在多线程环境中为每个线程提供独立的变量副本。ThreadLocal不是一种数据结构,而是一种解决线程间共享数据的方式,它提供了线程安全的局部...

    使用ThreadLocal管理“session”数据

    在Java编程中,ThreadLocal是线程局部变量的类,它提供了一种在多线程环境中为每个线程创建和维护独立副本的机制。ThreadLocal主要用于解决线程间的数据隔离问题,确保各线程拥有自己的变量副本,避免了数据共享带来...

    java中ThreadLocal类的使用

    Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...

    Quartz-ThreadLocal.rar

    这个压缩包 "Quartz-ThreadLocal.rar" 内含的学习资源很可能是关于如何在 Quartz 调度器中结合使用 ThreadLocal 的示例。 Quartz 的核心功能包括: 1. **作业与触发器**:在 Quartz 中,任务被称为“作业”(Job)...

    JDK的ThreadLocal理解(一)使用和测试

    **标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...

    Java中ThreadLocal的设计与使用

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,用于为每个线程提供独立的变量副本。理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ...

Global site tag (gtag.js) - Google Analytics