1.ThreadLocal实例
Num类
class IncreaseNum { ThreadLocal<Integer> num = new ThreadLocal<Integer>(); public Integer getNextNum() { if(num.get()==null){ //初始化是0 num.set(0); }else{ num.set(num.get() + 1); } return num.get(); } }
线程类
class IncreaseNumThread extends Thread { IncreaseNum entity; public IncreaseNumThread(IncreaseNum entity) { this.entity = entity; } @Override public void run() { for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName() + "的数字"+ entity.getNextNum()); }
测试类
public static void main(String[] args) { IncreaseNum entity = new IncreaseNum(); IncreaseNumThread thread1 = new IncreaseNumThread(entity); IncreaseNumThread thread2 = new IncreaseNumThread(entity); IncreaseNumThread thread3 = new IncreaseNumThread(entity); thread1.start(); thread2.start(); thread3.start(); } } }
结果
Thread-2的数字0 Thread-2的数字1 Thread-0的数字0 Thread-1的数字0 Thread-1的数字1 Thread-1的数字2 Thread-0的数字1 Thread-0的数字2 Thread-2的数字2
如果按照正常来说的话3个线程共享一个实例,数字应该从0-8,但是现在每个线程的数字都是从0-2.这就是ThreadLocal的作用。
2.ThreadLocal类介绍
早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思
API定义
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
主要方法get()
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
可以看出get方法和当前线程有关,用map来存储,当前线程作为key,然后赋值,当取值的时候取出来的和当前线程相关,而不会影响其他线程的值。
3.ThreadLocal和线程同步比较
1)在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
2)ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
ThreadLocal的应用场景:
1)Spring使用ThreadLocal解决线程安全问题
我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了
2)分页信息的存储
每次请求都带有自己的分页信息,这些请求是并发的,为了保证每次请求的分页信息相互不影响,可以采用ThreadLocal保证线程并发的安全。
相关推荐
Java ThreadLocal用法实例详解 Java ThreadLocal是Java中的一种线程局部变量机制,用于保存每个线程独有的数据,以避免线程之间的数据共享问题。ThreadLocal的基本使用非常简单,只需要定义一个ThreadLocal变量,...
在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,可能会引发线程安全问题。而`ThreadLocal`则提供了另一种...
当线程结束之前没有调用`remove`方法,ThreadLocal实例将无法被垃圾收集,因为它仍然在Thread的ThreadLocalMap中有一个引用。因此,需要在不再需要ThreadLocal变量时记得清理。 总之,Java中的ThreadLocal是处理...
例如,HibernateUtil类中会定义一个ThreadLocal变量来保存SessionFactory创建的Session实例,便于在多线程环境下安全地使用。 ```java public class HibernateUtil { private static final ThreadLocal<Session> ...
1. **避免共享ThreadLocal实例**:确保每个类都有自己的`ThreadLocal`实例,避免不同类之间共享`ThreadLocal`对象。 2. **谨慎使用继承**:如果`ThreadLocal`是在父类中定义的,子类可能会无意中访问到不属于当前...
例如,在Spring的DAO模板类中,尽管底层的数据连接或会话资源是非线程安全的,但是通过使用ThreadLocal,可以为每个线程绑定独立的数据连接或会话,使得多个DAO可以复用同一个模板实例而不会发生资源冲突,极大地...
Java ThreadLocal使用案例详解 Java ThreadLocal是Java语言中的一种机制,用于为每个线程提供一个独立的变量副本,以解决多线程环境下共享变量的线程安全问题。在本文中,我们将详细介绍Java ThreadLocal的使用案例...
在这个例子中,`UniqueThreadIdGenerator` 类使用 `ThreadLocal` 来为每个线程生成唯一的 ID。`initialValue()` 方法会在每个线程首次访问 `uniqueNum` 时被调用,返回一个递增的 ID。 5. **注意事项** - 虽然 `...
"Java 中ThreadLocal实例分析" Java 中的 ThreadLocal 实例分析是指在多线程环境下,如何使用 ThreadLocal 来实现线程安全。ThreadLocal 是 Java 中的一种机制,用于在多个线程中实现变量的隔离。 在上面的代码中...
### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...
### ThreadLocal核心概念详解 #### 一、ThreadLocal简介与重要性 ThreadLocal是一个非常重要的Java并发工具类,它的核心概念在于为每一个线程提供了一个独立的变量副本,从而避免了线程之间的数据竞争问题。这使得...
因此,不同线程访问同一个ThreadLocal实例时,它们看到的是各自的副本,互不影响。 ```java ThreadLocal<String> thl = new ThreadLocal(); thl.set("ThreadA variable"); ``` 在上述代码中,`thl`在每个线程中都...
在使用`ThreadLocal`时,一定要确保在恰当的时机清除其存储的引用,以避免长期持有不必要的类加载器实例,导致内存资源浪费。在Java EE环境中,尤其需要注意这类问题,因为容器的特殊性可能导致不易察觉的内存泄漏。...
这意味着每个线程都拥有ThreadLocal变量的私有实例,它们之间互不干扰。在Android中,ThreadLocal常被用来存储线程相关的数据,例如Handler中的Looper对象,因为Looper与线程紧密关联,每个线程通常只有一个Looper,...
`ThreadLocal`的工作原理是为每个线程创建一个单独的实例副本,这些副本存储在一个与线程相关的映射表中。当线程执行时,它首先查找自己的副本,如果没有,则会自动创建。 让我们通过一个简单的例子来理解`...
通过以上介绍,我们可以了解到 `ThreadLocal` 在处理多线程环境中提供了独特的数据隔离机制,常用于创建线程安全的工具类实例,或者在每个线程内部保存全局变量。正确使用和管理 `ThreadLocal` 是避免潜在问题的关键...
主要介绍了JAVA开发常用类库UUID、Optional、ThreadLocal、TimerTask、Base64使用方法与实例详解,需要的朋友可以参考下
在上述代码中,创建了一个ThreadLocal实例,然后在线程的run()方法中设置值,每个线程设置的数据只对自己可见,不会影响其他线程。这样既实现了数据共享(所有线程可以访问到ThreadLocal),又确保了对象独立(每个...
- 每个线程都拥有自己的 ThreadLocal 实例,这些实例是相互独立的,因此不存在线程安全问题。 - **使用场景:** - 当需要为每个线程分配独立的数据时,ThreadLocal 是一个很好的选择。 - 例如,在连接池管理、...