(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
ThreadLocal
文章目录
1.ThreadLocal是什么?
(1)线程本地变量,有些地方也叫做线程本地存储。
(2)ThreadLocal可以让每个线程拥有一个属于自己的变量的副本,不会和其他线程的变量副本冲突,实现了线程的数据隔离。
1.1使用ThreadLocal实现线程数据隔离案例
public class UseThreadLocal {
static ThreadLocal<String> threadLocal1 = new ThreadLocal<>();
static ThreadLocal<Integer> threadLocal2 = new ThreadLocal<>();
//自定义ThreadLoacal使用
//static MyThreadLocal<String> threadLocal1 = new MyThreadLocal<>();
/**
* 1.测试线程
* 1.1线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
*/
public static class PersonThread implements Runnable{
private int id;
public PersonThread(int id) {
this.id = id;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
threadLocal1.set("线程"+id);
/*
1.当前线程为线程1的时候,为线程1再添加一个数据,即为线程1的Entry[]数组中添加两个元素数据
2.而其他线程的Entry[]数组只放1个元素。
3.以此证明利用ThreadLocal可以实现线程数据隔离,每个线程只操作自己内部的数据,不会影响
到其他线程的数据。
*/
if(id == 1){
threadLocal2.set(id);;
}
System.out.println(String.format("%s:%s",threadName,threadLocal1.get()));
}
}
public void startThreadArray(){
Thread[] runs = new Thread[3];
//1.创建线程对象并放入线程数组
for(int i = 0 ; i < runs.length;i++){
runs[i] = new Thread(new PersonThread(i));
}
//2.取出线程对象并启动线程
for (int i = 0 ; i < runs.length;i++){
runs[i].start();
}
}
public static void main(String[] args) {
UseThreadLocal useThreadLocal = new UseThreadLocal();
useThreadLocal.startThreadArray();
}
}
2.自定义ThreadLocal实现线程数据隔离
/**
* 自己实现的ThreadLocal
* @param <T>
*/
public class MyThreadLocal<T> {
/**
* 存放变量副本的map容器,以Thread为键,变量副本为value
*/
private Map<Thread,T> threadMap = new HashMap<>();
/**
* 将当前线程传进去拿到值
* @return
*/
public synchronized T get(){
return threadMap.get(Thread.currentThread());
}
/**
* 1.以当前线程为键,以传入的值为value,保存这个线程到map容器中。
* 2.为确保线程安全,所有的方法都加上synchronized关键字。
* @param t
*/
public synchronized void set(T t){
threadMap.put(Thread.currentThread(),t);
}
}
3.自定义ThreadLocal需要面对的核心问题
(1)即在存放变量副本的容器Map<Thread,T> threadMap上面将会出线激烈的竟争。
(2)就如同抢蓝球,这个竟争是非常的激烈的。
(3)使用ThreadLocal就相当于给每一个人发一个蓝球,就相于把所有的蓝球编上号放到一个柜子里面,谁要用,去拿到这个柜子里面的蓝球,用完了又放回这个柜子里面,虽然说这些人不抢蓝球了,但是会抢这个柜子的钥匙。所以这个时候,它对于大的容器上面还是有竟争。所以JDK在内部实现的时候,它并没有按我们自定义的方式进行实现。
4.JDK中是如何实现ThreadLocal的线程数据隔离的
(1)ThreadLocal的set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
(2)哪个线程调用了set方法,就将当前线程作为参数传入一个getMap()方法,返回一个ThreadLocalMap
(3)getMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
(4)ThreadLocalMap是当前线程Thread类中的成员属性。
ThreadLocal.ThreadLocalMap threadLocals = null;
(5)ThreadLocalMap的定义
- 它是在ThreadLocal中定义的
- 在ThreadLocalMap中定义了一个Entry[] table的数组。
private Entry[] table;
- 这个Entry是ThreadLocal作为键,Object作为value.
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
(6)类的引用关系
public class Thread implements Runnable{
ThreadLocalMap threadLocals;
}
static class ThreadLocalMap{
private Entry[] table;
}
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
(7)调用ThreadLocal的set方法的时候,会发生什么事情呢?
- 首先线程已经有了。
- 在每一个线程的内部产生一个ThreadLocalMap对象实例
- 在ThreadLocalMap对象中有一个Entry[]数组类型的成员属性
- 当调用set方法往Entry[]中set的时候,就会放入元素。它的键就是threadLocal,而值是线程id。
- 为什么要用Entry[]数组?
ThreadLocal不会用一个容器来存,而是在Thread的内部,自己来保存变量的副本,因为一个线程是允许有多个ThreadLocal型的变量,所以它用了一个Entry[]数组来保存键为ThreadLoacal,值为Object的元素,由此实现了线程之间数据的完全隔离。
每一个线程访问自己的数据。
(8)在任何并发工具里面,ThreadLocal的性能一直是最强大的。
-
原因就是不需要跟别人去抢占资源了,所以性能就会得到大大的提高。
-
什么叫竞争?
就是多个线程抢一个东西叫竞争。
5.打赏鼓励
感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!