java中的锁

2019-11-23  本文已影响0人  北方_f6b4

工作中在遇到并发问题的时候一般通过加上重锁(synchronized, reentrantLock)或者使用cas无锁算法实现,甚至可以通过volietale关键字实现低并发下的安全或者是通过第三方如数据库来实现并发控制。关于java中的锁有很多维度,本文,就java中的锁,整理记录一下。

1 锁的分类和概念

     1.1:公平锁&&非公平锁

                公平锁是指多个线程获得对象锁是按照申请顺序来获得的。非公平锁是指等待线程获得锁并不是按照申请顺序获得的,这种情况加可能会出现饥饿现象,优点是吞吐量稍大。

synchronized:是一种非公平锁,因为他是通过可充入块原语monitorenter  monitorexit实现的,并没有实现aqs所以不能实现公平锁。

ReentrantLock是通过AQS实现线程调度的,在生成ReentrantLock的构造函数中可以指定使用非公平锁还是公平锁。

公平锁指定

       1.2  可重锁&&不可重入锁

可重入锁只是一个概念,就是当这个线程拥有这个锁的时候,这个线程可以再次获得这个锁(这个线程在外层获得了锁在内层还可以再次获得)。synchorized和reentrantLock都是可重入锁,不可重入锁可能会造成死锁。

  1.3 独享锁&&共享锁  

独享锁是指一个锁只能被一个线程所持有,共享锁指一个锁可以被多个线程所持有。Lock类里面的ReadWriteLock里面的读锁是共享锁,写锁是独享锁。   共享锁与独享锁也是通过AQS框架实现的

1.4 乐观锁悲观锁

     乐观悲观也是一种概念。乐观锁:是指面对并发问题时候,总是认为其是不会出现并发冲突的,采取的方式一般是执行后校验,如果校验发现出现了并发冲突,那么进行重试,如果没有发生并发冲突,其实就是没有加锁的。

 悲观锁:不管如何,就是对对象加锁。总是认为这一次操作一定会出现线程冲突。

   一般我们在有可能出现并发问题的地方就必须使用锁,但是当这种并发冲突出现的概率比较低的时候,使用乐观锁的效率会比较高,如果出现冲突的概率比较大,那么使用乐观锁会频繁的重试反而效率会低。

1.4分段锁

    分段锁其实是一种设计方式,不是一种具体的锁。jdk1.7的时候,ConcurrentHashMap就是实现分段锁来实现线程安全的。思路是将一个整体分段。每个段单独拥有一个锁标志,互不影响。也是锁细化的一种思想吧。但是其仍然是一种重量级锁,currentHashMap在jdk1.8的时候就放弃使用分段锁而使用无锁来实现并发安全的了。

1.5 自旋锁 

   自旋锁的概念是当线程需要去获得锁但是没有立即获得的时候,这个时候线程会持续的循环,不放弃cup。这种情况下有两个优点,首先由于是在自旋,其响应时间短 其次,减少了cpu上下文切换的时间。

  缺点:不放弃cpu,如果大量线程自旋,会增大cpu压力,浪费cpu。

 1.6 偏向锁&&轻量级锁&&重量级锁

这是相对于synchronized而言的,锁升级,对象的头字段内有一个字段是锁字段标志,其标志的就是这三个锁状态。

偏向锁是指一段同步代码一直被一个线程访问时候(没有竞争),这个线程就会自动获得锁,降低获得所的代价。当这段同步代码处在偏向锁状态,来了另外一个线程进行访问,这个偏向锁就会升级到轻量级锁,其他线程会通过自旋的方式来等待尝试获得锁,不会等待,提高性能。线程自旋一定程度的时候,就会进入阻塞状态,该锁就会膨胀成为重量级锁(悲观锁)。其他线程进行访问时候就会进入阻塞。


2 java锁优化

1 锁粗化:一般来说我们把锁细化是为了提高效率,但是在某些情况下,比如在循环里面频繁的加锁释放锁,加锁释放锁是需要系统调用cpu用户态到内核态切换的,所以我们要尽量减少加锁释放锁的次数。jvm在运行期间会自动优化,把一些不必要的加锁释放锁的操作合并,扩大锁的作用范围。

2 锁消除:jvm通过逃逸分析发现某些加锁模块根本不会出现线程竞争的可能,虚拟机有可能直接把这个锁去除。

 3锁的膨胀   偏向锁->轻量级锁->重量级锁  这个过程


3 通过java锁相关内容的感悟。

     1 java锁的概念,是我们必须要了解的,了解锁之后正确使用锁才能写出安全的代码。

      2 jvm做的锁优化:jvm层面的锁优化其实是在我们代码的锁使用不合理的情况加采取的一些运行期优化的措施,我们的目的就是不让jvm能够对我们的代码进行优化(让jvm优化说明我们自己写的代码不够优美高效),我们在并发编程的时候,就考虑到锁粗化,不给不会出现并发代码块加锁这些,合理正确使用锁,写出高效率的代码。

上一篇下一篇

猜你喜欢

热点阅读