开发者学堂课程【JDBC 数据库开发进阶:ThreadLocal】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/32/detail/689
ThreadLocal
内容介绍:
一、ThreadLocal 简介
二、API说明
一、ThreadLocal 简介
ThreadLocal 用于保存某个线程共享变量。在 Java 中,每个线程对象都有一个ThreadLocal,其中 key 就是一个 ThreadLocal ,而 Object就是线程的共享变量。
对于同一个 static ThreadLocal ,不同的线程只能从中 get , set , remove 自己的变量,而不会影响其他线程的变量。
在 Java 的多线程编程中,为保证多个线程对共享变量的安全访问,通常会使用synchronized 来保证同一时刻只有一个线程对共享变量进行操作。
这种情况下可以将类变量放到 ThreadLocal 类型的对象中,使变量在每个线程中都有独立拷贝,不会出现一个线程读取变量时而被另一个线程修改的现象。
最常见的 ThreadLocal 使用场景为用来解决数据库连接、Session 管理等。
代码示例:
package
cn
.
itcast
.
thread
;
import
org
.
junit
.
Test
;
/**
*
ThreadLocal
对象的用法
*
author cxf
*
*/
public
class
Demo1
{
@Test
public
void
fun1
()
{
ThreadLocal
<
string
>
tl
=
new
ThreadLocal
<
string
>(
);
tl
.
set
(
"hello"
);
//存
string s
=
tl
.
get
(
);
//取
tl
.
remove
()
;
//删
system
.
out
.
println
(
s
)
;
}
}
public
void
fun2
{
final
Map
<
Thread
,
string
>
map
=
new
HashMap
<
Thread,string
>(
)
;
map
.
put
(
Thread
.
currentThreglo
,
"hello"
);
system
.
out
.
println
(
map
.
getThread
.
currentThread
()
)
)
;
new
Thread
()
{
public
void
run
()
{
system
.
out
.
println
();
}
}.
start
()
;
new
Thread
(
o
{
public
void
run
()
{
tl
.
set
(
"内部类存"
);
system
.
out
.
println
(
"内容类:"
+
tl
.
get
());
}
}
try
{
Thread
.
sleep
(
1000
)
;
}
catch
(
InterruptedException
e
)
{
//TODo Auto-generated catch blocke
e
.
printstackTrace
()
;
}
}
/*ThreadLocal通常用在一个类的成员上
*多个线程访问它时,每个线程都有自己的副本,互不干扰!
*spring中把connection放到了ThreadLocal中!
*明天我们会再次修改Jdbcutils类!
*给它添加一个
*/
class
TL
<
T
>
{
private
Map
<
Thread
,
T
>
map
=
new
HashMap
<
Thread
,
T
>();
public
void
set
(
.
data
)
{
//使用当前线程做key
map
.
put
(
Thread
.
currentThread
()
,
data
)
;
}
public
Tget
(
)
{
return
map
.
get
(
Thread
.
currentThread
();
}
public
void
remove
()
{
map
.
remove
(
Thread
.
currentThread
()
);
} }
二、API说明
Threadlocal 类只有三个方法:
1.void set(T value):保存值;
将此线程局部变量的当前线程副本中的值设置为指定值。
许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。在程序中一般都重写 initialValue 方法,以给定一个特定的初始值。
2.void remove():移除值
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue 。
3.T get():获取值:
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
4.protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。
如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。若该实现只返回 null ;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。
通常,将使用匿名内部类。 initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
代码示例:
import java.util.Random;
public class TestTools {
public static void main(String[] args) {
MyThread th1=new MyThread();
th1.start();
MyThread th2=new MyThread();
th2.start();
}
}
class Tools{
private static Random rand=new Random();
private static ThreadLocal th=new ThreadLocal<>();
{
th.set(rand.nextInt(100));
//这里设置的就是当前线程保存的共享变量,这个共享变量不是之前的多线程之间的共享变量,而是同一个线程在整个生命周期中,使用的共享变量。
}
public static int getNumber(){
return th.get();
}
}
class MyThread extends Thread{
public void run(){
Tools.setNumber();
for (int i = 0; i <5 ; i++) {
int number=Tools.getNumber();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+":"+number);
}
}
}