标签:throw 限制 同步机制 ble 线程并发 创建 并发 利用 处理
threadlocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据
ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
做个不恰当的比喻,从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。
这里的这个比喻是不恰当的,实际上是ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。
ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。
ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文
提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用
总结:
1.线程并发:在多线程并发的场景下(单线程是用不到ThreadLocal的)
2.传递数据:我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量(和域对象有点相似)
3.线程隔离:每个线程的变量都是独立的不会互相影响(ThreadLocal的核心)
方法声名 | 描述 |
---|---|
ThreadLocal( ) | 创建ThreadLocal对象 |
public void set(T value) | 设置当前线程绑定的局部变量 |
public T get( ) | 获取当前线程绑定的局部变量 |
public void remove( ) | 移除当前线程绑定的局部变量 |
演示问题:
/*
需求:线程隔离
在多线程并发的场景下,每个线程中的变量都是相互独立
线程A: 设置(变量1) 获取(变量1)
线程B: 设置(变量2) 获取(变量2)
*/
public class MyDemo01 {
//变量
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) {
MyDemo01 demo = new MyDemo01();
//开启五个线程
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//每个线程:存一个变量,过一会取出这个变量
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("-----------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
});
//设置线程名字
thread.setName("线程"+i);
thread.start();
}
}
}
结果显示:
多运行几次,就会出现以上数据,每个线程存入的数据和取出的数据是不一致的,java中的线程调度是抢占式调度,本身具备随机性
这种情况就是线程不隔离
应该怎么解决呢?
利用ThreadLocal
ThreadLocal
使用ThreadLocal改进之后的代码
/*
需求:线程隔离
在多线程并发的场景下,每个线程中的变量都是相互独立
线程A: 设置(变量1) 获取(变量1)
线程B: 设置(变量2) 获取(变量2)
ThreadLocal:
1.set(): 将变量绑定到当前线程中
2.get(): 获取当前线程绑定的变量
*/
public class MyDemo01 {
ThreadLocal<String> t1 = new ThreadLocal<>();
//变量
private String content;
public String getContent() {
// return content;
String s = t1.get();
return s;
}
public void setContent(String content) {
// this.content = content;
//将变量content绑定到当前线程
t1.set(content);
}
public static void main(String[] args) {
MyDemo01 demo = new MyDemo01();
//开启五个线程
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//每个线程:存一个变量,过一会取出这个变量
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("-----------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
});
//设置线程名字
thread.setName("线程"+i);
thread.start();
}
}
}
再次运行,多运行几次,增加出现问题的几率
结果正常,哪怕加上thread.sleep(200); 结果也还是正常的
ThreadLocal解决了线程隔离的这个需求
使用synchronized也可以完成隔离线程的需求
public class MyDemo02 {
//变量
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static void main(String[] args) throws InterruptedException {
MyDemo02 demo = new MyDemo02();
//开启五个线程
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//每个线程:存一个变量,过一会取出这个变量
//使用synchronized代码块来完成需求
synchronized (MyDemo02.class){
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("-----------------");
System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());
}
}
});
//设置线程名字
thread.setName("线程"+i);
thread.start();
thread.sleep(200);
}
}
}
那么ThreadLocal与synchronized的区别是什么呢?
右边的代码加了synchronized锁,线程只能一个一个去执行,排队进行访问,效率低,让我们的程序失去了并发性
左边没有加锁,一样可以并发执行
虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题,
但是两者处理问题的角度和思路不同
synchronized | ThreadLocal | |
---|---|---|
原理 | 同步机制采用“以时间换空间”的方式,只提供了一份变量,让不同的线程排队访问 | ThreadLocal采用“以空间换空间”的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰 |
侧重点 | 多个线程之间访问资源的同步 | 多线程中让每个线程之间的数据相互隔离 |
小结:
synchronized锁是解决线程的同步问题,线程失去并发性,效率低
ThreadLocal可以使程序拥有更高的并发性,能够保证程序执行的效率
详细的ThreadLocal以及与synchronized的区别
标签:throw 限制 同步机制 ble 线程并发 创建 并发 利用 处理
原文地址:https://www.cnblogs.com/liqiliang1437/p/13347051.html