synchronized

线程阻塞挂起再唤醒的消耗比自旋锁要高吗?

线程阻塞挂起再唤醒的消耗比自旋锁要高。

原因如下:

当线程需要获取锁时,如果使用自旋锁,它会一直尝试获取锁,直到锁被释放,这样可以避免线程的阻塞,提高了效率。但是,如果锁被占用的时间很长,线程会一直占用CPU资源,导致CPU利用率较高。

而当线程需要获取锁时,如果使用阻塞挂起的方式,线程会在等待队列中等待,直到锁被释放。这种方式避免了线程一直占用CPU资源,但是线程需要被挂起和唤醒,会产生额外的系统开销,导致效率较低。

因此,一般情况下,如果锁的占用时间较短,使用自旋锁可以提高效率;如果锁的占用时间较长,使用阻塞挂起的方式可以降低CPU利用率。

线程自旋需消耗 cup的,如果一直获取不到锁,则线程长时间占用CPU自旋,需要设定一个自旋等待最大事件在最大等待时间内仍未获得锁就会停止自旋进入阻塞状态。


为什么Mutex Lock效率低下

Mutex Lock 的效率低下主要是由于以下几个原因:

系统调用开销:Mutex Lock 是一种基于系统调用的锁,需要进行系统调用来获取和释放锁。系统调用涉及到用户态和内核态之间的切换,开销较大,会降低锁的效率。

内核态操作:Mutex Lock 的获取和释放需要在内核态进行,需要进行内核态和用户态之间的切换,也会降低锁的效率。

等待唤醒开销:当一个线程持有 Mutex Lock 时,其他线程需要等待该线程释放锁。当锁被释放时,需要通知等待的线程,这个过程需要进行等待和唤醒操作,会带来额外的开销。

竞争激烈时开销更大:当多个线程竞争同一个 Mutex Lock 时,会发生锁的争用,导致效率进一步下降。
因此,Mutex Lock 的效率在高并发、竞争激烈的情况下会更加低下,这时候可以考虑使用其他更加高效的锁,如 Spin Lock、Read-Write Lock 等。


请详细叙述下synchronized的加锁流程

synchronized 是 Java 中的一种内置锁,可以用来保护共享资源的访问。当一个线程需要获取 synchronized 锁时,会经历以下几个步骤:

判断锁状态
当一个线程尝试获取 synchronized 锁时,会首先判断锁状态。如果锁未被占用,即锁状态为“未锁定”,那么该线程将获得锁,并将锁状态设置为“已锁定”,然后进入临界区。如果锁已经被占用,那么该线程将进入等待队列,等待锁被释放。

获取锁
如果锁状态为“未锁定”,那么该线程将获得锁,并将锁状态设置为“已锁定”。同时,该线程将获得锁的所有权,其他线程无法访问该锁,直到该线程释放锁。

进入临界区
当一个线程获得锁后,它将进入临界区,执行共享资源的访问操作。在临界区内,其他线程无法访问共享资源,只有当前线程可以访问。

释放锁
当一个线程执行完临界区内的操作后,需要释放锁。当锁被释放时,锁状态将被设置为“未锁定”,等待队列中的线程将被唤醒,并且其中一个线程将获得锁的所有权,继续执行临界区内的操作。
需要注意的是,synchronized 锁是可重入的,即同一个线程可以多次获取同一个锁,而不会被阻塞。在一个线程持有锁的情况下,如果它再次尝试获取同一个锁,它将立即获得锁,而不是被阻塞。在这种情况下,锁计数器将加 1,表示此时该线程已经获得了锁的所有权。当线程执行完临界区内的操作后,它需要释放锁,同时锁计数器将减 1,表示该线程已经释放了一次锁。只有当锁计数器减为 0 时,锁才会被完全释放,其他线程才能获得锁的所有权。


synchronized 在jdk1.6后做了哪些改动

在 JDK 1.6 中,synchronized 做了以下几个改动:

优化了锁的实现:JDK 1.6 之前的 synchronized 实现中,锁的状态只有两种:锁定和非锁定。在锁定状态下,任何线程都无法获取锁,而在非锁定状态下,任何线程都可以获取锁。这种实现方式有一个缺点,即在锁竞争激烈的情况下,会导致大量线程在锁上自旋,浪费 CPU 资源。为了解决这个问题,JDK 1.6 引入了偏向锁和轻量级锁。偏向锁是指当锁只有一个线程竞争时,使用的是一种乐观锁策略,不需要进行同步操作,从而提高了效率。轻量级锁是指当锁竞争不激烈时,使用的是一种自旋锁策略,可以避免线程阻塞,提高了效率。只有在锁竞争激烈的情况下,才会使用传统的重量级锁。

引入了锁升级:在 JDK 1.6 之前,synchronized 锁只有两种状态:锁定和非锁定。在锁定状态下,任何线程都无法获取锁,而在非锁定状态下,任何线程都可以获取锁。这种实现方式效率较低,因为在锁竞争激烈的情况下,会导致大量线程在锁上自旋,浪费 CPU 资源。为了解决这个问题,JDK 1.6 引入了锁升级的概念,即当线程在获取锁时,会先尝试使用偏向锁或轻量级锁,如果获取锁失败,则升级为重量级锁。这种方式可以根据锁竞争的情况,选择不同的锁实现方式,从而提高效率。

修复了锁重入的问题:在 JDK 1.6 之前,当一个线程持有锁时,如果再次尝试获取锁,会导致死锁。在 JDK 1.6 中,synchronized 修复了这个问题,允许线程重入锁,即同一个线程可以多次获取同一个锁,而不会被阻塞。在一个线程持有锁的情况下,如果它再次尝试获取同一个锁,它将立即获得锁,而不是被阻塞。


偏向锁是什么

header-icon
偏向锁是 Java 中的一种锁优化技术,旨在提高单线程访问同步代码块的性能。在偏向锁的实现中,当一个线程访问一个同步代码块时,会自动获得锁,并将锁的标记记录在对象头中。当该线程再次访问同一个同步代码块时,无需竞争锁,直接进入临界区,从而避免了锁竞争的开销。
偏向锁的实现过程如下:

当一个线程访问一个同步代码块时,偏向锁会记录下该线程的 ID,以及对象头中的标记位,表示该对象已经被该线程偏向过。

当该线程再次访问同一个同步代码块时,偏向锁会检查对象头中的标记位,如果标记位为偏向锁,并且记录的线程 ID 与当前线程相同,那么该线程无需竞争锁,直接进入临界区。

如果对象头中的标记位不是偏向锁,或者记录的线程 ID 与当前线程不同,那么偏向锁会升级为轻量级锁或重量级锁,让多个线程竞争锁。
偏向锁的优点在于,当同步代码块只有一个线程访问时,可以避免锁的竞争,从而提高性能。同时,偏向锁的撤销操作也比较轻量级,只需要更新对象头中的标记位即可。
需要注意的是,偏向锁只适用于访问同步代码块的线程数比较少的情况,如果多个线程同时访问同一个同步代码块,那么偏向锁的性能就会下降,因为需要升级为轻量级锁或重量级锁,从而引入锁竞争的开销。因此,在选择锁的实现方式时,需要根据实际情况进行评估和选择。


偏向锁101

轻量锁000

重量锁010

无锁001

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值