原子性
这个定义是一种规定,描述了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变量来实现锁的操作。
ThredLocal
- ThredLocal保证线程安全是不让多线程去操作临界资源
/** * @author 舒一笑 * @date 2023/5/27 */ public class Test11 { static ThreadLocal threadLocal1 = new ThreadLocal(); static ThreadLocal threadLocal2 = new ThreadLocal(); public static void main(String[] args) { threadLocal1.set("舒一笑"); threadLocal2.set("每天写代码"); Thread thread = new Thread(()->{ System.out.println(threadLocal1.get()); System.out.println(threadLocal2.get()); }); thread.start(); System.out.println("主线程"+threadLocal1.get()); System.out.println("主线程"+threadLocal2.get()); } }
- 原理分析
- 弱引用会被线程回收两头都会回收,key就没有了,所以在使用之后需要remove掉value防止内存泄露
- 最后完整版应该加上这样两句话