juc总结

Lock

  1. ReentrantLock: 独占锁
    加锁 加锁失败的话, 会创建节点绑定在锁维护的队列节点上,并进行阻塞睡眠,当unlock 时,唤醒队列上的线程

  2. newCondition await signal
    用法:可被指定唤醒, lock1 lock后, 才能使用生成的condition await 后释放锁, 被其他线程唤醒后将conditionNode 上添加到 等待队列节点的尾部

  3. ReentrantReadWriteLock 读写锁

LockSupport: LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程

CountDownLatch countDown await

CyclicBarrier await

Semaphore acquire release

T1 重入锁 加锁后调用的方法加通向的锁, 锁计数+2
加锁方法碰到异常后会释放锁,其他线程会访问到错误的同步代码块数据 进行事务回滚

MyContainer4 互相叫醒 wait 释放锁 叫醒的时候要把锁在还给它
5、CyclicBarrier和CountDownLatch(await countDown)的区别

两个看上去有点像的类,都在java.util.concurrent下,都可以用来表示代码运行到某个点上,二者的区别在于:

(1)CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行;CountDownLatch则不是,某线程运行到某个点上之后,只是给某个数值-1而已,该线程继续运行

(2)CyclicBarrier只能唤起一个任务,CountDownLatch可以唤起多个任务

(3)CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了

synchronized和ReentrantLock的区别

synchronized是和if、else、for、while一样的关键字,ReentrantLock是类,这是二者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:

(1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
Lock lock = new ReentrantLock(); lock.lock();lock.unlock() 手动加锁手动释放, 遇到异常也不释放,所以写在finally
可以尝试lock locked = lock.trylock(5, TimeUnit.Seconeds) 在指定时间内获得锁,获得不到就往下执行
或者主动让别人把锁释放(lock.lockInterruptibly 加锁 对外面的interrupt打断作出响应)
ReentrantLock( new ReentrantLock(true);公平锁 但是效率低谁等时间长谁用 而不是抢占式)
wait 往往和while使用
lock.newCondition() 可以指定叫醒哪个 await signalAll

(2)ReentrantLock可以获取各种锁的信息

(3)ReentrantLock可以灵活地实现多路通知

另外,二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word,

//A线程获得锁后, 其他线程获取 获取不到会将自己添加到队列中, 等待 A 执行完成后 A 去唤醒队列上的第一个线程,

    // 如果 期间使用 到condition 会 await 会将当前线程添加到conditon 持有 await 节点上, 然后将lock 上等待的线程唤醒
    // B 线程解锁时 不会吧A 线程唤醒, 因为A不在等待队列上, 只能用 condition signal 来唤醒, 唤醒后,会将condition 上的waiter 增加到lock 的等待线程上

countdownlatch 则是 一次性锁, await 后会 增加到等待队列上, coundown 达到数量减到0后,会唤醒所有等待队列上的线程
CyclicBarrier 到达后会await 暂停 达到数量后 会被唤醒, 其实内部也就是condition, 达到一个await

FutureTask 相当于占位符, get 的时候,如果任务没有执行完成,get的线程会加入到等待队列上,并休眠, 当 run 完成时 回去唤醒等待队列上的线程

ForkjoinPool RecursiveTask

Semaphore 创建的时候声明大小, acquire 超过这个数量的时候就睡眠 release 会去唤醒这些等待的线程

Semaphore 和 ReentrantLock 区别:

  1. 锁可重入, 信号量重入可能会造成死锁, 没法释放
  2. 死锁恢复, 信号量在任意线程可释放许可,可释放, 锁 只能持有者才能释放
  3. 抛出异常,其他线程调用release ,不会 锁会爆 unlock
  4. 信号量任意线程可修改信号量, 锁只有持有线程才能修改

何时使用, 需要非持有释放的话,可使用信号量, 否也就用锁

posted @ 2022-10-11 20:48  jojoworld  阅读(39)  评论(0编辑  收藏  举报