threadLocal是线程封闭的一种实现。
线程封闭:当访问共享的可变数据,通常需要使用同步。一种避免使用同步的方法就是不共享。如果单线程内访问数据,就不需要同步。这种技术就是线程封闭。局部变量和ThreadLocal就是这种机制的一种实现。
其实就是每个thread有自己的副本,不共享。
下面看下代码(也是参考了网上其他人的):
public class SequenceNumber {
//①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
// private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){
// public Integer initialValue(){
// return 0;
// }
// };
//也可以用下面这个方法
private static ThreadLocal<Integer> seqNum = ThreadLocal.withInitial(() -> 0);
//②获取下一个序列值
public int getNextNum(){
seqNum.set(seqNum.get()+1);
return seqNum.get();
}
public static void main(String[ ] args){
SequenceNumber sn = new SequenceNumber();
//③ 3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
@Override
public void run(){
//④每个线程打出3个序列值
for (int i = 0; i < 3; i++) {
System.out.println("thread["+Thread.currentThread().getName()+
"] sn["+sn.getNextNum()+"]");
}
}
}
}
结果:
Connected to the target VM, address: 'javadebug', transport: 'shared memory'
thread[Thread-0] sn[1]
thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
thread[Thread-1] sn[1]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
线程不安全版:
package ThreadLocalTest.threadLocalSequenceNumber;
/**
* @author huql
* @date 2021/7/24 21:18
* @comments:
*/
public class SequenceNumber {
private static Integer seqNum = 0;
// ②获取下一个序列值. 线程不安全
public int getNextNum(){
seqNum = seqNum + 1;
return seqNum;
}
public static void main(String[ ] args){
SequenceNumber sn = new SequenceNumber();
//③ 3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
@Override
public void run(){
//④每个线程打出3个序列值
for (int i = 0; i < 3; i++) {
System.out.println("thread["+Thread.currentThread().getName()+
"] sn["+sn.getNextNum()+"]");
}
}
}
}
结果:
ThreadLocalTest.threadLocalSequenceNumber.SequenceNumber
Connected to the target VM, address: 'javadebug', transport: 'shared memory'
thread[Thread-0] sn[1]
thread[Thread-2] sn[3]
thread[Thread-2] sn[4]
thread[Thread-2] sn[5]
thread[Thread-1] sn[2]
thread[Thread-1] sn[6]
thread[Thread-1] sn[7]
thread[Thread-0] sn[8]
thread[Thread-0] sn[9]
第二个例子:
public class ThreadLocalStudy {
static ThreadLocal<String> localLocalVar = new ThreadLocal<String>();
static void printString(String str) {
//打印本地变量
System.out.println(str + ":" + localLocalVar.get());
//移除本地变量
localLocalVar.remove();
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
localLocalVar.set("localLocalVar1");
//调用打印方法
printString("thread1");
printString("after remove : " + localLocalVar.get());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
localLocalVar.set("localLocalVar2");
//调用打印方法
printString("thread2");
//打印本地变量
printString("after remove : " + localLocalVar.get());
}
});
t1.start();
t2.start();
}
}
输出:
Connected to the target VM, address: 'javadebug', transport: 'shared memory'
thread1:localLocalVar1
after remove : null:null
thread2:localLocalVar2
after remove : null:null
Disconnected from the target VM, address: 'javadebug', transport: 'shared memory'
参考:
https://zhuanlan.zhihu.com/p/390527514
https://cloud.tencent.com/developer/article/1657723
https://www.jianshu.com/p/537167d42c82