成都网站建设设计

将想法与焦点和您一起共享

Java并发编程——ThreadLocal-创新互联

ThreadLocal

10年积累的网站设计制作、成都网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有武都免费网站建设让你可以放心的选择与我们合作。

概述

一、对ThreadLocal的理解

1.1 ThreadLocal在JDK中的定义

1.2 应用场景

二、深入分析ThreaLocal类

2.1 get()

2.2 setIntialValue()

2.3 ThreadLocal类是如何为每个线程创建变量副本

三、ThreadLocal的应用场景

3.1 数据库连接问题

3.2 Session管理

3.3 Thread-per-Request(一个请求对应一个服务器线程)

四、ThreadLocal的一般使用步骤

概述

本文借鉴了Java 并发编程这篇博主专栏的文章,他的专栏写的很好,推荐!

ThreadLocal 又名 线程局部变量 ,是 Java 中一种较为特殊的线程绑定机制,可以为每一个使用该变量的线程都提供一个变量值的副本,并且每一个线程都可以独立地改变自己的副本,而不会与其它线程的副本发生冲突。

一般而言,通过 ThreadLocal 存取的数据总是与当前线程相关,也就是说,JVM 为每个运行的线程绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种 隔离机制 。

如果某个变量要被某个线程独享,那么我们就可以通过ThreadLocal来实现本地存储功能;

一、对ThreadLocal的理解

1.1 ThreadLocal在JDK中的定义

每个线程都有关于该 ThreadLocal变量 的私有值 ,并且对其他线程是不可见的;

ThreadLocal 可以给定一个独立于变量的初始值,这样每个线程就会获得这个初始化值的一个拷贝,并且每个线程对这个值的修改对其他线程是不可见的;

ThreadLocal的一个重要作用是就是将类的状态与线程关联起来,解决方案就是在这个类中定义一个 private static ThreadLocal 实例;

1.2 应用场景

类 ThreadLocal 主要解决的就是为每个线程绑定自己的值,以方便其处理自己的状态;

形象地讲,可以将 ThreadLocal变量 比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。例如,以下类用于生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 uniqueNum.get() 时分配的,在后续调用中不会更改;

二、深入分析ThreaLocal类

ThreadLocal中,一共提供了四个方法:

public T get() { }

public void set(T value){ }

public void remove(){ }

protected T initialValue{ }

1

2

3

4

get() 获取ThreadLocal变量在当前线程中保存的值;

set() 设置ThreadLocal在当前线程的值;

remove() 用来移除当前线程中相关ThreadLocal变量;

initialValue() 是一个protected方法,一般需要重写;

2.1 get()

源码如下:

public T get(){

Thread t = Thread.currentThread();//获取当前线程对象

ThreadLocalMap map = getMap(t);

if(map!=null){

//从当前线程的ThreadLocalMap获取该thread-local variable对应的entry

ThreadLocalMap.Entry e = map.getEntry(this);

if(e!=null)

return (T)e.value;//取得目标值

}

return setInitialValue();

}

1

2

3

4

5

6

7

8

9

10

11

2.2 setIntialValue()

private T setIntialValue(){

T value = initialValue(); //默认实现返回null

Thread t = Thread.currentThread();//获得当前线程;

ThreadLocalMap map = getMap(t);//得到当前线程ThreadLocalMap类型域threadLocals

if(map!=null)

map.set(this,value);//该 map 的键是当前 ThreadLocal 对象

else 

createMap(t,value);

return value;

}

1

2

3

4

5

6

7

8

9

10

initialValue()

protected T initialValue() {

    return null;            // 默认实现返回 null

}

1

2

3

createMap()

void createMap(Thread t, T firstValue) {

    t.threadLocals = new ThreadLocalMap(this, firstValue); // this 指代当前 ThreadLocal 变量,为 map 的键  

}

1

2

3

2.3 ThreadLocal类是如何为每个线程创建变量副本

每个线程内部有一个 ThreadLocal.ThreadLocalMap 类型的成员变量 threadLocals,这个 threadLocals 存储了与该线程相关的所有 ThreadLocal 变量及其对应的值(”ThreadLocal 变量及其对应的值” 就是该Map中的一个 Entry)。 Key 是 ThreadLocal 变量, Value 是该 ThreadLocal 变量对应的值;

初始时,Thread里面的threadlocals为空,当ThreadLocal变量调用**get()方法或者set()**就会对Thread类中的threadlocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的值为value,存到 threadLocals;

然后在当前线程里面,如果要使用ThreadLocal对象,就可以通过get方法获得该线程的threadLocals,然后以该ThreadLocal对象为键取得其对应的 Value,也就是ThreadLocal对象中所存储的值;

三、ThreadLocal的应用场景

Java 中,类 ThreadLocal 解决的是变量在不同线程间的隔离性。最常见的 ThreadLocal 使用场景有 数据库连接问题、Session管理等。

3.1 数据库连接问题

private static ThreadLocal connectionHolder = new ThreadLocal() {

public Connection initialValue() {

    return DriverManager.getConnection(DB_URL);

}

};

public static Connection getConnection() {

return connectionHolder.get();

}

1

2

3

4

5

6

7

8

9

3.2 Session管理

private static final ThreadLocal threadSession = new ThreadLocal();

public static Session getSession() throws InfrastructureException {

Session s = (Session) threadSession.get();

try {

    if (s == null) {

        s = getSessionFactory().openSession();

        threadSession.set(s);

    }

} catch (HibernateException ex) {

    throw new InfrastructureException(ex);

}

return s;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

3.3 Thread-per-Request(一个请求对应一个服务器线程)

在经典Web交互模型中,请求的处理基本上采用的都是“一个请求对应一个服务器线程”的处理方式,因此就可以将请求设置成类似ThreadLocal的形式,这样,当某个服务器线程来处理请求时,就可以独享该请求的处理;

四、ThreadLocal的一般使用步骤

ThreadLocal使用步骤一般分为三步:

创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx;

提供一个获取要隔离访问的数据的方法 getXxx(),在方法中判断,若 ThreadLocal对象为null时候,应该 new() 一个隔离访问类型的对象;

在线程类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象,不会交叉。

————————————————

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


当前文章:Java并发编程——ThreadLocal-创新互联
转载源于:http://chengdu.cdxwcx.cn/article/eohis.html