什么是线程安全

多线程执行某段代码,不对这段代码进行同步处理、线程间的协调,程序运行的结果仍与预期一致,这就是线程安全。

多线程编程的三个核心概念

  • 原子性: 同数据库事务的原子性,一些操作要么全部成功,要么全部失败,经典的例子就是银行转账。
  • 可见性:多线程并发访问共享变量时,某个线程对共享变量的更新,其他线程能立即看到这个更新。

在java中,对象储存在主内存。每个线程都有自己的工作内存,线程从主内存读取对象到工作内存,执行更新对象操作,立即更新工作内存,但没有立即刷新到主内存,故其他线程仍然读到旧值。

  • 顺序性: 指程序顺序执行代码中的操作。

编译器、处理器会进行指令重排序,优化代码,以提高处理速度。程序实际的执行顺序可能与代码中的不一样,但编译器、处理器保证结果是一样的。这不会影响单线程的正确性,但会影响多线程的正确性。

要保证多线程程序正确执行,必需保证原子性、可见性、顺序性。

synchronized、ReentrantLock

使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、顺序性。使用synchronized、ReentrantLock获取到锁,线程更新共享变量后会立即刷新到主内存,其他线程获取到同一个锁时会将缓存失效并从主内存读取新值,保证了可见性。注意是同一个锁才能保证可见性。synchronized、ReentrantLock的性能较差,因为一个线程占有锁,其他线程会阻塞,线程的挂起和唤醒会降低处理速度。

原子操作类

使用AtmoicInteger、AtmoicLong、AtmoicReference来保证原子性,底层使用CAS(compare and swap)。CAS(compare and swap)是非阻塞同步的计算机指令, 它有三个操作数,内存位置、旧的预期值、新值,当内存位置的值与旧的预期值相等时才将新值存入内存位置。对于ABA问题,可使用AtomicStampedReference,通过引入版本号解决。

volatile

volatile能保证可见性和一定程度的顺序性。
变量被volatile修饰时,线程对变量进行写操作时jvm会向处理器发送lock前缀指令,lock前缀指令相当于内存屏障。
内存屏障的功能

  • 写操作修改的值会立即刷新到主内存,并设置其他线程的缓存无效,线程读取变量必需从主内存读取新值,保证了可见性。
  • 禁止指令重排序,后面的指令不能再内存屏障之前,前面的指令不能再内存屏障之后,保证一定程度的顺序性。

ThreadLocal


每个线程Thread都有一个ThreadLocalMap的变量threadLocals。
ThreadLocal不存储对象,对象存储于每个线程的ThreadLocalMap。ThreadLocal就是对当前线程的ThreadLocalMap进行增删改查。

ThreadLocal中的内存泄露问题

ThreadLocalMap的key是弱引用,这个key就是ThreadLocal对象。
若ThreadLocal变量被设置为null后,且没有强引用指向这个ThreadLocal对象,根据垃圾回收的可达性分析算法,该ThreadLocal对象将被回收,ThreadLocalMap中某个Entry的key就会变为null,不能再使用的value无法释放内存,造成内存泄露。
ThreadLocalMap的补救措施,调用getEntry()、set()、remove()方法会清除key为null的entry。但不调用这三个方法仍然会有内存泄露问题,因此当ThreadLocal使用完时应当remove掉。

如何实现线程安全

  • 互斥同步: 使用synchronized、ReentrantLock作用于一段代码,同一时刻只能有一个线程能进入这段代码,保证了原子性、可见性、顺序性。
  • 非阻塞同步: CAS(compare and swap)是非阻塞同步的计算机指令, 它有三个操作数,内存位置、旧的预期值、新值,当内存位置的值与旧的预期值相等时才将新值存入内存位置。对于ABA问题,可使用AtomicStampedReference,通过引入版本号解决。
  • 无同步: 使用ThreadLocal将共享变量的可见性限制在线程内部,每个线程维护一个共享变量的副本,线程间相互隔离,不再争用数据。

线程安全 如何实现线程安全 volatile ThreadLocal相关推荐

  1. 线程执行完之后会释放吗_java多线程并发:CAS+AQS+HashMap+volatile+ThreadLocal,乐分享...

    CyclicBarrier.CountDownLatch.Semaphore 的用法 CountDownLatch(线程计数器 ) CountDownLatch 类位于 java.util.concu ...

  2. java volatile线程可见_volatile-验证线程之间的可见性

    由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Java内存 模型中规定所有变量都存储在主内存,主内存是共享内 ...

  3. 在使用线程池时应特别注意对ThreadLocal的使用

    使用ThreadLocal并且有线程池时要特别注意,ThreadLocal是以线程为key的,而线程池里面的线程是会被重新利用的,所以如果有使用线程池并且使用ThreadLocal来保存状态信息时要特 ...

  4. 获取父线程 java_java子线程中获取父线程的threadLocal中的值

    我们都知道线程本地变量表也就是ThreadLocal在我们做线程级的数据隔离时非常好用,但是有时候我们会想如何让子线程获取到父线程的ThreadLocal,其实在线程中除了ThreadLocal外还有 ...

  5. java和线程相关的关键字有哪些_Java中有哪些机制来保证线程安全?synchronized关键字和volatile关键字...

    想要解决线程安全问题,首先要知道为什么会造成线程不安全? 在单线程中,我们从来没有提到个线程安全问题,线程安全问题是只出现在多线程中的一个问题.因为多线程情况下有共享数据,每个线程都共享这些数据并对这 ...

  6. 20200428 线程安全(上)--彻底搞懂volatile关键字

    计算机在处理数据的过程中为什么会出现线程不安全的问题. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中会涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存) ...

  7. JDK源码系列:子线程如何继承父线程上通过ThreadLocal绑定的数据

    上一篇中老吕介绍了ThreadLocal线程数据绑定的原理,今天聊聊父子线程之间如何继承ThreadLocal上维护的数据. 开发过程中异步执行任务有两种情况,第一种情况是 主线程 通过 new Th ...

  8. java传递父线程对象_父子线程和线程池如何实现threadLocal变量传递

    上一次我们看了ThreadLocal的原理和实现,今天我们看看下面几个问题: 1.多线程中父子线程,子线程如何获取父线程的变量?2.主线程和线程池的线程本地副本变量如何实现复用隔离? 一.Inheri ...

  9. volatile能保持线程安全吗_Java线程安全(volatile synchronized)

    总结 volatile不能保证线程安全而synchronized可以保证线程安全.volatile只能保证被其修饰变量的内存可见性,但如果对该变量执行的是非原子操作线程依旧是不安全的.而synchro ...

最新文章

  1. 面试中多说这么一句话,薪水直接涨5k
  2. 对话微软黄学东:语音语言技术是镶在 AI 皇冠上的明珠
  3. xp系统本地服务器环境配置,Windows XP安装Apache环境图文详解Windows服务器操作系统 -电脑资料...
  4. 个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能...
  5. 在真实工作中的编程是怎么样的,与学校里有什么不同?
  6. C++ limits头文件的用法numeric_limits
  7. mybatis $和#源代码分析
  8. go 错误处理总结
  9. 【记录】Docker安装后出现 Cannot connect to the Docker daemon
  10. vue避免重新渲染_详解强制Vue组件重新渲染的方法
  11. Centos/Linux在线环境下载安装包,到离线环境安装,并解决依赖问题
  12. POJ 2817 状态DP 字符串找最多的重复
  13. css绘制向左三角形_CSS绘制三角形—border法
  14. iOS:Tagged Pointer
  15. 算法图解 PDF 原文内容分享
  16. DHT爬虫和使用BEP协议完成metadata的下载(BT下载)
  17. 聊聊FPGA学习与开发板的那些事儿
  18. 教你如何快速提取视频文案
  19. HDU-1253-胜利大逃亡
  20. html 块元素 css,HTML和CSS - 内嵌块元素的问题

热门文章

  1. 探究Visual Studio项目的当前目录
  2. NetCore基于Roslyn的动态编译实现
  3. 在种地这件事上,AI能取代中国人的种族天赋么?
  4. Redis分布式锁 分段加锁思想实现 分段锁
  5. C#创建Encoding.ASCII的.txt文件
  6. 辽宁工程技术大学本科毕业论文答辩和论文选题PPT模板
  7. 郑州海关销毁近2万张“问题地图” 重约5.3吨
  8. 朱大能求职之旅-为什么使用消息队列?消息队列有什么优缺点?Kafka/Activemq/Rabbitmq/Rocketmq优缺点对比?
  9. c语言双截龙_双截龙招式表
  10. 【hadoop】Hadoop 面试题总结