并发编程 线程安全——Java锁概念
Java锁概念
在Java中 保证线程安全的方案分为两种:同步、无同步、
造成线程安全问题的原因就是:多线程情况下共享变量的写操作不安全 所以解决方案也就是针对共享的变量进行的 同步共享变量 或者 不同步共享变量
同步:
-
互斥(阻塞):互斥是实现同步的一种手段 属于悲观的并发策略
多线程并发访问共享数据时 保证共享数据在同一时刻只被一个线程使用
临界区、互斥量和信号量都是主要的互斥实现方式Java中实现互斥的手段:
- synchronized 关键字
- lock 接口
互斥最主要的问题就是进行
线程阻塞和唤醒
所带来的性能问题 -
非阻塞:基于冲突检测的乐观并发策略
非阻塞的同步 其实就是在多线程访问共享变量的时候 先操作的线程会成功 后面的线程会失败 而失败的线程并不会阻塞挂起 而实采取其他的补偿措施 比如不断重试直到成功
非阻塞的实现 CAS:
- CAS指令需要有3个操作数,分别是内存地址(在java中理解为变量的内存地址,用V表示)、旧的预期值(用A表示)和新值(用B表示)
- CAS指令执行时,CAS指令指令时,当且仅当V处的值符合旧预期值A时,处理器用B更新V处的值,否则它就不执行更新,但是无论是否更新了V处的值,都会返回V的旧值,上述的处理过程是一个原子操作。
CAS的缺点:
-
ABA问题:因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
ABA问题的解决思路:使用版本号 记录修改次数
在Java中
java.util.concurrent.atomic
包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的:-
基本类型
-
AtomicBoolean
- 布尔类型原子类 -
AtomicInteger
- 整型原子类 -
AtomicLong
- 长整型原子类.......
-
无同步:
-
对象不共享
直接不使用共享变量
-
不可变对象
多线程对共享变量只能进行读操作
-
线程本地变量
直接把变量交给线程封闭起来 这样也不会被其他线程共享 自然也就不会有安全问题
总结:
- Java中线程安全的解决方案可以简单的理解为 同步 不同步 两种 --> 针对共享变量
- 在同步方案中又分为 互斥同步(悲观实现) 和 非阻塞同步(乐观实现) 两种 --> 针对同步方式
- 而不同步方案 其实就是只对共享变量进行读操作 或者直接没有共享变量 --> 针对程序设计