您的位置 首页 java

Java中各种锁的理解

1.分类简介

编程中其实有很多锁的概念,不仅仅是 java ,而这些锁的概念是根据不同的性质分类而得到的。

2.详解

2.1 悲观锁和乐观锁

悲观锁和乐观锁是一种广义概念,体现的是看待线程同步的不同角度。

  • 悲观锁

概念:悲观锁认为自己在使用数据的时候一定有别的 线程 来修改数据,在获取数据的时候会先加锁,确保数据不会被别的线程修改。

锁实现:关键字 synchronized 、接口Lock的实现类

适用场景:写操作较多,先加锁可以保证写操作时数据正确

  • 乐观锁

概念: 乐观锁 认为自己使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据

锁实现:CAS算法,例如ActomicInteger类的原子自增是通过CAS自选实现

适用场景:读操作较多,不加锁的特点能够使其读操作的性能大幅提升

2.2 自旋锁

描述:是指当一个线程在获得锁的时候,如果锁一旦被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,自旋知道获取到锁才会提出循环。

意义:自旋锁不会使线程状态发生切换。不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快

缺点:如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗 CPU 。使用不当会造成 CPU使用率 极高。

自旋锁和CAS的关系是什么? CAS是实现自旋锁的基础。基本CAS操作+循环就可以实现自旋锁。

自旋锁一般不需要自己写,因为有很多前人写了比较有名的自旋锁。

例如:CLHLock——CLH锁是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋,获得锁。

JAVA并发包的AQS的设计是对CLH锁进行了优化或者说变体。

2.3 读写锁 (读锁/写锁)

描述:synchronized和RentrantLock都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。

锁实现:ReentrantReadWriteLock

使用ReentrantReadWriteLock实现一个并发环境下安全的缓存类示例:

上述示例中, Cache 组合一个非线程安全的 HashMap 作为缓存的实现,同时使用读写锁的读锁和写锁来保证Cache是线程安全的。在读操作get(String key)方法中,需要获取读锁,这使得并发访问该方法时不会被阻塞。写操作put( String key, Object value)方法和clear()方法,在更新HashMap时必须提前获取写锁,其他读写操作才能继续。Cache使用读写锁提升读操作的并发性,也保证每次写操作对所有的读写操作的可见性,同时简化了编程方式。

文章来源:智云一二三科技

文章标题:Java中各种锁的理解

文章地址:https://www.zhihuclub.com/192867.shtml

关于作者: 智云科技

热门文章

网站地图