线程安全问题
- 主要是指多个线程对同一个对象的实例变量进行操作的时候,会出现值被更改,值不同步。
- 线程安全体现:
- 原子性
- 可见性
- 有序性
原子性
- 要么全部成功,要么全部失败
- Java两种方式实现原子性:
- 使用锁
- CAS指令
- 锁具有排他性,保证共享变量在某一个线程只能被同一个线程访问
- CAS指令直接在硬件层次上实现的。
可见性
- 多线程的时候,一个线程对某个共享变量进行更新之后,要通知其他线程知道该变量值已经发生改变。
- 因为可见性的问题可能导致其他线程读取到旧数据,产生脏读。
有序性
- 在什么情况下一个处理器上运行的一个线程所执行的内存访问操作,在另外一个处理器运行的其他线程看来是乱序的
- 乱序是指内存访问操作的顺序看起来发生了变化
重排序
- 这种一个处理器上执行的多个操作,在其他处理器来看它的顺序与目标代码指定的顺序可能不一样,这种现象称为重排序
- 编译器可能为改变两个操作的先后顺序,处理器也可能不会按照目标代码的顺序执行
指令重排序
- 在源码顺序与程序顺序不一致,或者程序顺序与执行顺序不一致情况下,就发生了指令重排。
- 指令重排不会对单线程的程序结果正确性产生影响,但是可能会导致多线程程序出现非预期结果。
Java内存模型
JVM与计算机的关系
JVM抽象
线程同步
线程同步机制简介
- 线程同步机制是一套用于协调线程之间的数据访问的机制.该机制可以保障线程安全
- 同步机制包括:锁、volatile、final、static、以及相关的 API,如 Object.wait()/Object.notify()等
锁概述
- 锁可以理解为对共享数据进行保护的一个许可证,一个线程只有在持有许可证(锁)的情况才能对共享数据进行访问,一个锁只能被一个线程持有
- 一个线程在访问共享数据之前必须要先获得锁;获得锁的线程被称为锁的持有线程。
- 锁具有排他性,就是一个锁一次只能被一个线程只有,这种锁就陈伟排它锁或者互斥锁。
- JVM把锁分为内部锁和显示锁。内部锁通过synchronized实现;显示锁通过java.util.concurrent.locks.Lock 接口的实现类实现。
锁的作用
- 可以实现对共享数据的安全访问。保证线程的原子性、可见性、有序性
- 使用锁保证线程的安全性:
- 这些线程在访问共享数据的时候必须使用同一把锁
- 即使是读取共享数据的线程也需要使用同步锁。