java多线程学习(三) 之 ThreadLocal

ThreadLocal 中文可以叫 线程变量

官方解释

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

这个类提供一个线程局部变量,意思就是变量只在该线程内可见,对于每个线程都可以用get和set方法获取属于这个线程自己的变量。ThreadLocal变量通常定义在那些想和线程绑定的类里面,例如访问者的ID,事务ID等等。

官方举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.concurrent.atomic.AtomicInteger;
 
public class ThreadId {
     private static final AtomicInteger nextId = 
                                       new AtomicInteger(0);
 
     private static final ThreadLocal<Integer> threadId =
         new ThreadLocal<Integer>() {
             @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();
     }
 }

其中threadId就是一个线程变量。具体的使用可以是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args)
{
  for (int i = 0; i < 5; i++)
  {
     final int num = i;
     new Thread()
     {
 
         @Override
         public void run()
         {
            System.err.println("线程" + num + ":" + ThreadId.get());
            next();
         }
 
         private void next()
         {
            System.err.println("线程" + num + ":" + ThreadId.get());
         }
 
        }.start();
    }
}

输出:
线程4:1
线程4:1
线程2:3
线程2:3
线程1:4
线程3:2
线程3:2
线程0:0
线程0:0
线程1:4

你会发现每个线程都有个对应的ThreadId,在同一个线程内部ThreadId是唯一的,此时你可以理解线程变量,ThreadLocal变量为每个线程保存一份变量,相互隔离,相互独立的.
你也可以这样理解ThreadLocal里保存了一个Map,key是线程的id,value是你要保存的东西。当在一个线程里调用ThreadLocal方法的时候,它就是到这个map里取key等于本线程id对应的value值,实际上JDK也是这样做的。

解释:initialValue是ThreadLocal的一个方法,当线程第一次调用get()的,如果之前没有调用set方法,就会调用一次initialValue方法,初始化一个值。

线程变量的用处在于,在一个线程内部可能代码逻辑非常复杂,然而你又想在线程中传递变量,如果是使用方法的参数的方式,就要一层层传递下去,而线程变量让代码变得简洁一些。

一些JAVA框架的功能也是使用线程变量来实现的,例如数据库连接池里的事务的保证,如何保证在一个方法里取到的是相同的连接,在方法一些列数据库操作结束的时候对该连接进行提交或者回滚呢?就是使用的线程变量,当发现一个方法需要支持事务的时候,java框架就会把进入方法之后获取的数据库连接放到线程变量里,当你在这个方法里任何地方再去调用数据库操作的时候,都是使用的同一个连接,当方法结束的时候,如果中间没有异常,框架就帮你提交数据,否则对之前的操作进行回滚操作,这样就做到了事务的隔离,实现了事务的功能。

留言

提示:你的email不会被公布,欢迎留言^_^

*

验证码 *