栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

关于Java锁的一些知识

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于Java锁的一些知识

1.自旋锁和非自旋锁 2.自旋锁的好处

阻塞和唤醒线程都是需要高昂的开销的,如果同步代码块中的内容不复杂,那么可能转换线程带来的开销比实际业务代码执行的开销还要大。

在很多场景下,可能我们的同步代码块的内容并不多,所以需要的执行时间也很短,如果我们仅仅为了这点时间就去切换线程状态,那么其实不如让线程不切换状态,而是让它自旋地尝试获取锁,等待其他线程释放锁,有时只需要稍等一下,就可以避免上下文切换等开销,提高了效率。

自旋锁的好处,就是自旋锁用循环去不停地尝试获取锁,让线程始终处于 Runnable 状态,节省了线程状态切换带来的开销。

3.自旋锁的缺点

虽然避免了线程切换的开销,但是它在避免线程切换开销的同时也带来了新的开销,因为它需要不停得去尝试获取锁。如果这把锁一直不能被释放,那么这种尝试只是无用的尝试,会白白浪费处理器资源。也就是说,虽然一开始自旋锁的开销低于线程切换,但是随着时间的增加,这种开销也是水涨船高,后期甚至会超过线程切换的开销,得不偿失。

4.自旋锁适用场景

自旋锁适用于并发度不是特别高的场景,以及临界区比较短小的情况,这样我们可以利用避免线程切换来提高效率。

可是如果临界区很大,线程一旦拿到锁,很久才会释放的话,那就不合适用自旋锁,因为自旋会一直占用 CPU 却无法拿到锁,白白消耗资源。

5.synchronized和volatile区别

synchronized可以保证事件的原子性和可见性。volatile只能保证事件的可见性。 6.锁升级机制

偏向锁

线程来之后不加锁,记录线程的id。下次再有线程进来的时候,认为这是上次进来的线程,如果还是上次进来的线程就继续运行不考虑加锁。如果是新的线程不是原来的线程就进行一个锁升级。

自旋锁

使用场景(执行时间短,线程少,使用自旋锁)当有线程将对象锁住之后,自旋锁在外面不断徘徊判断是否能拿到这个锁,当自旋十次还拿不到,执行锁升级。

重量级锁

使用场景(执行时间长,线程多,使用os锁)经过os进入等待队列里 7.乐观锁

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。

CAS 有效地说明了”我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”

ABA问题如何解决
添加版本号或时间戳 8.LongAdder原理

LongAdder内部维护一个Cells数组,每个Cell里面有一个初始值为0的long型变量,在同等并发量的情况下,争夺单个变量的线程会减少,这是变相的减少了争夺共享资源的并发量,另外**多个线程在争夺同一个原子变量时候,如果失败并不是自旋CAS重试,而是尝试获取其他原子变量的锁,**最后当获取当前值时候是把所有变量的值累加后再加上base的值返回的。

与AtomicInteger区别
AtomicInteger采用CAS算法。 9.ReentrantLock

需要手动加锁解锁,可采用公平锁或非公平锁机制;

采用CAS结构。

10.CountDownLatch

这个类使一个线程等待其他线程各自执行完之后再执行;

是通过程序计数器来实现的,计数器的初始值是线程的数量。当每个线程开始执行之后,计数器的值就减1,当计算器的值为0的时候,在等待的线程就可以重新开始工作了。

//参数count为计数值
public CountDownLatch(int count) {  }; 

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };   
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//将count值减1
public void countDown() { };
11.CyclicBarrier

这是一个同步辅助类,它允许一组线程相互等待,直到到达某个公共的屏障点,然后才会继续下一步行动。

//parties:参与线程个数
//barrierAction:最后一个到达线程要做的任务
public CyclicBarrier(int parties);
public CyclicBarrier(int parties, Runnable barrierAction);

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
使用场景:

用于多线程计算数据,最后合并计算结果的场景。

CyclicBarrier与CountDownLatch区别:

CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。 12.ReadWriteLock

当读数据时为共享锁,当写数据时为互斥锁。

13.LockSupport

LockSupport是一个线程阻塞的工具类,它的所有方法都是静态方法。可以在线程的任意位置阻塞。

//阻塞当前线程
public static void park();
//唤醒线程
public static void unpark(Thread thread);

与notify/wait 区别在于:notify只能随机选择一个线程唤醒,无法唤醒指定的线程,unpark却可以唤醒一个指定的线程。

14.可重入锁

线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/709021.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号