原子性
这个定义是一种规定,描述了Java中的理想就是为了能实现一个操作不能分割,不可中断,一个线程在执行的时候,另一个线程不会去影响他。
Java中的原子性可以理解为多线程操作临界资源,预期的结果和最终的结果一致。
- 原子性被破环的演示
如何保证并发编程中的原子性
- 通过加锁的方式实现
CAS
CAS是compare and swap 是一条CPU级别的并发原语,CAS操作包括三个步骤:比较内存中的值、判断是否相等,如果相等则交换新值;如果不相等,则不做任何操作。这个操作是原子性的,即在执行过程中不会被其他线程中断。
- 在Java中有使用基于Unsafe类提供关于CAS的操作方法。通过JVM帮助我们实现对CAS操作cpu的汇编指令。
- CAS 需要注意的是他着重点 是比较和交换 ,值从哪里来需要我们自己获取
- CAS的最主要应用就是实现乐观锁和锁自旋
CAS操作的时候只能使用对一个变量是原子性的,无法实现对多个
ABA问题:不符合原子操作
- 解决方案:加入版本号
CAS锁自旋时间过长:
CAS基本都需要自旋,又遇上高并发就会陷入忙等待的状态,进程虽然繁忙但是无法前进
Lock锁
- Lock是一个接口,我们使用的是他的一些实现类
- 并发较多的情况下推荐使用ReentrantLock锁
public class Test10 {
private static int count;
/**
* ReentrantLock 是一个对象,使用的时候要把他new出来
*/
private static ReentrantLock lock = new ReentrantLock();
public static void increment(){
lock.lock();
// 万一出错之后lock之后不会自动释放锁这一点和sy...不一样,需要在finally中释放锁资源
try {
count++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 100; i++) {
increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100 ; i++) {
increment();
}
});
thread.start();
thread2.start();
thread.join();
thread2.join();
System.out.println(count);
}
}
ReentrantLock可以直接对比synchronized,在功能上来说,都是锁。
但是ReentrantLock的功能性相比synchronized更丰富。
ReentrantLock底层是基于AQS实现的,有一个基于CAS维护的state变量来实现锁的操作。