解决线程不安全

发布时间 2023-12-04 14:20:44作者: 林浅

1.破坏临界资源

(临界资源破坏了 原子性 可见性 有序性)  直接不使用临界资源

2.只读

  使用final,只读 不写

3.局部变量

  每个线程的局部变量会存在栈帧中,会在每个线程的栈帧内存中被创建多份,因此不存在共享。

ThreadLocal

  ThreadLocal也就是线程本地变量。如果你创建了⼀个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的⼀个本地拷⻉,多个线程操作这个变量的时候,实际是操作⾃⼰本地内存⾥⾯的变量,从⽽起到线程隔离的作⽤,避免了线程安全问题。

实际应⽤

  实际开发中我们真正使⽤ThreadLocal的场景还是⽐较少的,⼤多数使⽤都是在框架⾥⾯。最常⻅的使⽤场景的话就是⽤它来解决数据库连接、Session管理等保证每⼀个线程中使⽤的数据库连接是同⼀个。 从数据库连接池中获取⼀个Connection对象,在JDBC规范中并没有要求这个Connection⼀定是线程安全的。

  数据库连接池通过线程封闭技术,保证⼀个Connection对象⼀旦被⼀个线程获取之后,在这个Connection对象返回之前,连接池不会将它分配给其他线程,从⽽保证了Connection对象不会有并发问题。

  线程封闭技术的⼀个具体实现是我们上⾯提到的局部变量的使⽤(栈封闭),还有⼀种需要提⼀下,即ThreadLocal类。

ThreadLocal怎么实现?

  ThreadLocal是Java中所提供的线程本地存储机制,可以利⽤该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意⽅法中获取缓存的数据

  ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对象)中都存在⼀个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值

ThreadLocal内存泄露是怎么回事?

如果在线程池中使⽤ThreadLocal会造成内存泄漏,因为当ThreadLocal对象使⽤完之后,应该要把设置的key,value,也就是Entry对象进⾏回收,但线程池中的线程不会回收,⽽线程对象是通过强引⽤指向ThreadLocalMap,ThreadLocalMap也是通过强引⽤指向Entry对象,线程不被回收,Entry对象也就不会被回收,从⽽出现内存泄漏。

解决办法是在使⽤了ThreadLocal对象之后,⼿动调⽤ThreadLocal的remove⽅法,⼿动清除Entry对象。