关于 J.U.C 的基本概念

一些基本的概念

乐观锁和悲观锁

乐观锁是在使用资源之前不上锁的处理方式。悲观锁是在使用资源之前要上锁。乐观锁和悲观锁的定义是使用场景来说。 在资源竞争不激烈的情况下,说明资源比较充足,我们保持一种乐观的态度,所以在使用之前不用上锁。悲观锁是在资源竞争激烈的情况下,说明资源竞争比较激烈,所以在使用资源之前要上锁。上锁之后的目的就是告诉前来竞争的线程,你们不用抢占资源了,这个资源在用了,而且用的时间不会短,你就去排队吧。

公平锁和非公平锁

公平锁就是获得锁的机会大家都是一样的,大家都在一种 FIFO 的队列里面排着,不许插队。非公平锁是允许插队。

自旋锁

自旋锁是一种无锁使用共享资源的方法,只有检测到某个条件成立的条件下,线程才会使用共享资源。CAS 就是自旋锁的一种实现。自旋就是线程不断的通过循环来检测条件是否成立,如果不成立,则线程进入下次循环,就像在哪里空转一样,所以叫自旋。还是挺形象的。

自旋锁有三种实现:TicketLock、CLHlock和MCSlock

自旋锁还两个问题,是 ABA 问题和原子更新问题。

ABA 问题是,条件成立的问题,可能此条件非彼条件。例如,监测 a = 10 往下执行,当时这个 10 已经被其他线程改动过了。值还是那个值,但是此值非比值,其实我们想要的是 10 ,是没有其他线程改过的值。通常的做法是为变量加上版本号来区分。当变量做了变更之后,它的版本好也要变更。

原子更新问题,当线程处理好了 ABA 问题,判断之前的值没有变化,进行更改操作,怎么保证更好操作的原子性呢?Java 是采用汇编的 lock 为 exchg 上锁的方式。所以 Java 的 CAS 也使用 OS 内核态的命令。

偏向锁、轻量级锁、重量级锁

这三个锁是 synchronized 锁升级的三个阶段。jvm 会根据申请锁的线程数来决定是否升级锁。

偏向锁是在对象头中的标记,此标记记录上次进入锁的线程号,如果申请锁的线程和这个标记上的线程号相同的话,则线程直接进入。

轻量级锁,当有第二个线程过来的时候,偏向锁就会升级为轻量级锁,轻量级锁是使用头信息中的前30作为 CAS 的目标内存。线程的栈帧上弄一个 locker record ,这个 locker record 相当于上锁对象的头信息中的 Mark word 的副本。申请锁的线程会使用 CAS 的方式来尝试修改对象头的 mark record 指向申请锁线程的 lock record。如果能修改成功,则申请到了锁。最后将 ower thread 指向锁对象的头。两个线程的竞争,有 50% 的概率竞争到锁,得到的锁的概率还是蛮大的。

轻量级锁也可以重入的。只是在拷贝一份对象头的 mark word 之后,不在将 ower 指向锁对象的对象头。

轻量级锁是不会阻塞线程的,没有获得锁的线程会自旋等待的。

当线程自旋次数太多(1.6之太多的标志是有线程自旋了 6 次,也可以设置自旋的次数,在 1.6 之后,自调节了)的时候,说明资源竞争更加的激烈了,JVM 会将轻量级锁升级为重量机锁。重量机锁依赖于操作系统的 Mutex 这种锁机制,没有申请到锁的线程会被阻塞住。这种锁需要系统调用。系统调用就会有用户态和内核态的切花。这种锁对占用锁时间就长的场景非常友好。但是对那些占用锁时间比较短的场景就不友好了。原因是线程从阻塞态到运行态的切换也是需要时间的,就像在游乐城拍段,排队一小时,快乐一分钟。需要等这么长的时间,还不如阻塞线程让它等待,不要再占用CPU资源了。 如果用户线程所以的操作都能在用户态搞定,那是不是就能节约出大量的时间,这就是协程出现的目的。

影响多线程的几个因素:

  1. 线程切换的成本
  2. 占用 CPU 的时长

这里要讲到线程的类型:CPU型和IO型

CPU 型是在时间片内,大部分时间都在使用 CPU 。

IO型式在时间片内,大部分时间都在等待 IO。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值