天天看点

多线程并发ThreadLocal

今天要讲的话题就是网上Java一直热议的多线程并发问题的解决!这个问题在不知道的时候是很高大上,但是了解了之后也就那么一回事,原理要懂!

我们知道传统web容器进行http请求处理的时候,是需要用到httpServletRequest、httpServletResponse,而servelet对象是一个无状态的单列对象(singleton),对于同一个servlet对象的多个请求,servlet的service方法将在一个多线程的环境中并发执行,所以web容器默认采用单实例(单servlet实例)多线程的方式来处理Http请求,这时候就会造成多线程之间的数据不安全,每个线程都可以修改同一个变量的数据!针对这个问题的解决方案,一般很多程序员会采用两种方案,第一:“规避问题”,但它是非语法检查级别的禁止(此问题不能根本上杜绝程序员犯这样的错误);第二:在整个请求周期中引入ThreadLocal模式,使整个过程的对象访问都线程安全化。所以要引用优秀的编程思想threadLocal.

多线程并发问题的具体解决方案细节:java.lang.ThreadLocal类。ThreadLocal类在维护变量时,实际使用了当前线程(Thread)中的一个叫做ThreadLocalMap的独立副本。每个线程可以独立修改属于自己的副本而不会互相影响。关于ThreadLocalMap介绍,如下:

1、ThreadLocalMap变量属于线程的内部属性,不同的线程拥有完全不同的ThreadLocalMap变量;

2、线程中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或者get操作时创;

3、在创建ThreadLocalMap之前,会首先检查当前线程中的ThreadLocalMap变量是否存在,如果不存在则创建一个;如果存在,则使用当前线程已创建的ThreadLocalMap

4、使用当前线程的ThreadLocalMap的关键在于使用当前的ThreadLocal的实列作为key进行存储。

可能讲到这里,很多人就会问,那怎么使得多线程数据之间是安全的,这就是我接下来要说的——ThreadLocal数据访问隔离,它做到了两个方面:

第一:纵向隔离——线程与线程之间的数据访问隔离。因为每个线程在进行对象访问时,访问的都是各个线程自己的ThreadLocalMap;

第二:横向隔离:同一个线程中,不同的ThreadLocal实列操作的对象之间互相隔离ThreadLocalMap采用ThreadLocal实列作为key来保证。

在同一个线程不同开发层次中共享数据,往往使用ThreadLocal模式(设计模式),可以对执行逻辑与执行数据进行有效解耦。接下来介绍实现他的两个主要步骤:

第一:建立一个类,并在其中封装一个静态的threadLocal变量,使其成为一个共享数据环境;

第二:在类中实现访问静态ThreadLocal变量的静态方法(设置和取值)。

然而,又有人会问,使用上面那些是因为线程不安全的情况下实施的,那么在线程安全的时候就不要,那我怎么去区分是否是线程安全呢!这个问题很好解决,因为不存在线程安全问题的方面总结起来也就那么几点:

1、方法签名中的任何参数变量;

2、处于方法内部的局部变量;

之所以上面那些是线程安全的,因为都处于方法体的内部!