Java ThreadLocal示例及使用方法总结

一、概述

ThreadLocal的名称比较容易让人误解,会认为其是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量。

其设计的初衷是为了解决多线程编程中的资源共享问题。提起这个,大家一般会想到synchronized,synchronized采取的是“以时间换空间”的策略,本质上是对关键资源上锁,让大家排队操作。而ThreadLocal采取的是“以空间换时间”的思路,为每个使用该变量的线程提供独立的变量副本,在本线程内部,它相当于一个“全局变量”,可以保证本线程任何时间操纵的都是同一个对象。

 二、实例

下面用一个实例阐述ThreadLocal的使用方法

创建一个Context类,其中含有transactionId属性。 

 1 package com.vigar;
 2 
 3 public class Context {
 4 
 5     private String transactionId = null;
 6     
 7     public String getTransactionId() {
 8         return transactionId;
 9     }
10 
11     public void setTransactionId(String transactionId) {
12         this.transactionId = transactionId;
13     }
14 }

创建MyThreadLocal做为容器,将一个Context对象保存于ThreadLocal中

 1 package com.vigar;
 2 
 3 public class MyThreadLocal {
 4     public static final ThreadLocal userThreadLocal = new ThreadLocal();
 5     public static void set(Context user) {
 6     userThreadLocal.set(user);
 7     }
 8      
 9     public static void unset() {
10     userThreadLocal.remove();
11     }
12      
13     public static Context get() {
14     return (Context)userThreadLocal.get();
15     }
16 }

多线程客户端程序,用于测试

 1 package com.vigar;
 2 
 3 import java.util.Random;
 4 
 5 public class ThreadLocalDemo extends Thread {
 6 
 7     public static void main(String[] args) {
 8             Thread threadOne = new ThreadLocalDemo();
 9             threadOne.start();
10             Thread threadTwo = new ThreadLocalDemo();
11             threadTwo.start();
12     }
13     
14     @Override
15     public void run() {
16             // 线程
17             Context context = new Context();
18             Random random = new Random();
19             int age = random.nextInt(100);
20             context.setTransactionId(String.valueOf(age));
21             
22             System.out.println("set thread ["+getName()+"] contextid to " + String.valueOf(age));
23             // 在ThreadLocal中设置context
24             MyThreadLocal.set(context);
25             /* note that we are not explicitly passing the transaction id */
26             try {
27                 Thread.sleep(1000);
28             } catch (InterruptedException e) 
29               {  
30                 e.printStackTrace();
31             }
32             
33             new BusinessService().businessMethod();
34             MyThreadLocal.unset();
35             }
36     }

模拟业务层,在某处读取context对象

1 package com.vigar;
2 public class BusinessService {
3     public void businessMethod() {
4         Context context = MyThreadLocal.get();
5         System.out.println(context.getTransactionId());
6         }
7 }

程序输出:

set thread [Thread-0] contextid to 32
set thread [Thread-1] contextid to 89
32
89

三、总结
ThreadLocal使用步骤

1.建立ThreadLocal容器对象A,其中对需要保存的属性进行封装。并提供相应的get/set方法(全部为static)

2.在客户端程序中,用A.setxxx, A.getXXX访问相应数据,即可保证每个线程访问的是自己独立的变量


 参考文献:

 1. 深入研究java.lang.ThreadLocal类_leizhimin_51CTO博客

 2. http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/

分类: corejava-基础java底层并发编程

标签: threadlocal

上一篇:浅谈threadlocal


下一篇:2021年12月1日30道面试题