JUC学习笔记

volatile

java虚拟机提供的轻量级的同步机制

  • 保证可见性
  • 不保证原子性
  • 🈲指令重排

JMM内存模型

  • 可见性
  • 原子性
  • 有序性

CAS

比较并交换compareAndSwap,是一条CPU并发原语,比较当前工作内存与主内存的值,如果相同则执行相关操作,如果不同则继续比较直到主内存与工作内存中的值一致为止。

atomicInteger用CAS不用synchronized的原因:

  1. synchronized对整段操作加锁,在竞争条件下会阻塞等待资源,如果竞争不到资源返回失败,降低并发性,而CAS可以相对减少阻塞时间
  2. CAS是一条CPU并发原语(用于判断当前工作内存中的值与主内存中值是否一致,如果是则更新,这个过程是原子的,即执行过程连续,不允许被中断
  3. CAS通过调用unsafe类(可以直接操作内存数据,内部方法都是native修饰),根据内存偏移地址获取数据

缺点:

  • 循环时间长,开销大
  • 只能保证一个共享变量的原子性
  • ABA问题
    cas算法实现一个重要前提是,线程在某时刻从主内存中取出数据并在当前时刻进行比较并替换,这个时间差可能会导致数据在中间过程发生过变化。即可能某个线程cas操作成功,但并不代表其中间过程是没有问题的。
    ⤵️
    原子引用:
    AtomicReference
    ⤵️
    时间戳原子引用(ABA问题的解决)
    AtomicStampedReference

集合类不安全的问题:

  • 故障现象: java.util.ConcurrentModificationException
  • 导致原因 并发争抢修改导致
  • 解决方案
    ①vector类等线程安全的容器替换
    ②Collections工具类:
    Collections.synchronizedList(new Arraylist<>())
    JUC解决方法:
    CopyOnWriteArraylist类:
    new CopyOnWriteArraylist<>()
    写时复制,应用读写分离的思想
    🚩 CopyOnWrite容器即写时复制容器,往一个容器添加元素时,不直接往当前容器的Object[]添加,而是先将当前容器进行copy,在新的容器中添加元素,元素添加完成后,将原容器的引用指向新的容器。
    这样做的好处是可以对容器进行并发读,而不需要加锁,读和写使用不同的容器

公平锁和非公平锁

是否按照申请锁的先来后到的顺序获取锁,并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁,非公平锁的优点是吞吐量比公平锁大。对于synchronized而言,也是一种非公平锁。

  • 公平锁,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就加入到等待队列中,以后会按照FIFO规则从队列中取到自己;
  • 非公平锁,线程到来时尝试占有锁,如果尝试失败,就再采用类似公平锁的方式。

可重入锁(递归锁)

‌reentrantLock和synchronized就是典型的可重入锁
‌可重入锁最大的作用是防止死锁
‌指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,进入内层方法也会自动获取锁。
🚩线程可以进入任何一个它已经拥有的锁所同步着的代码块。
(加锁和解锁次数只要匹配就可以)

自旋锁(spinlock)

是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU

独占锁(写锁)/共享锁(读锁)/互斥锁

  • ‌独占锁:指该锁一次只能被一个线程所持有,sychronized和ReentrantLock是独占锁。
  • 共享锁:指该锁可以同时被多个线程所持有。
    ‌对ReentantReadWriteLock,其读锁是共享锁,写锁是独占锁。该锁的共享锁可以保证并发读非常高效,读写,写读,写写的过程都是互斥的。
  • 🚩多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行,但是,如果有任何一个线程想去写共享资源,就不应该再有其他线程可以对该资源进行读或写。
    ‌🚩写操作:原子+独占,整个过程必须是完整的统一体,中间不许被分割,不许被打断

CountDownLatch & CyclicBarrier & Semaphore

CountDownLatch

(秦灭六国,一统天下)
计数器,直到计数为0时await()方法才不被阻塞。
让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,调用线程会被阻塞。其他线程调用countDown方法会将计数器减1(调用countDown方法的线程不会被阻塞),当计数器的值变为0时,因调用await方法被阻塞的线程被唤醒,继续执行。

CyclicBarrier

(集齐七颗龙珠就能召唤神龙)
可循环使用的屏障。它要做的事是,让一组线程到达一个屏障(也叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才能继续干活,线程进入屏障通过CyclicBarrier的await方法。

CyclicBarrier与CountDownLatch的区别:CyclicBarrier可重复多次,而CountDownLatch只能是一次.

Semaphore

信号量,可以代替synchronized和lock,信号量设置为1退化成synchronized
信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,一个是用于并发线程数的控制。

正常的锁(concurrency.locks或synchronized锁)在任何时刻都只允许一个任务访问一项资源,而 Semaphore允许n个任务同时访问这个资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值