java锁的终极大整理

java锁的终极大整理

一、概述

java中是在是有太多太多的锁,相信很多人在面对某个锁的时候在概念上可能有些模糊,所以我才会写这边文章,梳理一下自己脑海里的概念,如果那哪里有疏漏,诸位请指出

二、分类

 首先将锁分为概念上的锁、有具体实现类的锁、锁的底层原理锁、数据库锁

  概念上的锁:悲观锁、乐观锁、互斥锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、死锁,

  有具体实现类的锁:synchronized、reentrantLock、ReadWriteLock。

  原理锁:自旋锁,自适应自旋锁 、可重入锁、轻量级锁、偏向锁

  数据库锁:行锁、表锁、页锁

三、具体解释概念上的锁

  悲观锁:每次都假设数据会被别的线程偷偷修改,所以一次只让一个线程进入,其他线程等待如synchronized、reentrantLock。

  乐观锁:每次都假设我的数据都不会被修改,所以每次都不阻止其他线程进入,人好不代表没心眼,每次更新数据时,会通过数据版本库以及CAS机制,看看数据有没有被修改,没有就更新数据,有就自旋重新获取数据,如AtomicInteger等确保原子操作的类,valitile关键字是一种同步机制,不是锁,解决不了原子性问题。

  互斥锁:在任何时刻,只让一个线程操作数据,最明显的就是写锁,以及Semaphore通过设置信号量,来限制一个线程来操作数据。

  公平锁:先到先得reentrantLock通过构造函数来设置是否公平,默认非公平

  非公平锁:每个线程过来,都会先自旋尝试直接抢占锁资源,抢不到,再进入竞争队列当中去排队。synchronized

  共享锁:通过控制线程来实现的概念锁,也就是允许多个线程进入的都是共享锁,比如读锁。

  独占锁:通过控制线程来实现的概念锁,也就是说每次只允许一个线程进入的锁就是独占锁,如synchronized、renntrantlock、写锁

  重量级锁:重量级锁是因为线程的切需要从用户态切换到核心态,可以理解成线程的运行在用户态,权限较低,线程的切换,需要切换到核心态,获取更高的权限才可以,这种切换需要依赖操作系统,所以往往重量级锁线程之间的切换消耗大于操作代码的消耗,这也是synchronized为什么效率低下的原因。如、synchronized、renntrantlock。

  死锁:不解释,字面意思。线程之间互相把对方堵死在线程里面同归于尽。

四、有具体实现类的锁。

  synchronized:重量级锁、独占锁、互斥锁、悲观锁。释放锁的过程依赖于JVM

  renntrantlock:重量级锁、独占锁、互斥锁、悲观锁。释放锁的过程由自己实现,可Thread.interrupt()方法中断

中断。

五、原理上的锁

  自旋锁:目前来看几乎所有的锁的底层都有自旋锁,有java编写,是个native,给其他的锁提供了自旋的功能。可以设定自旋的时间。

  自适应自旋锁:对自旋锁的优化,具备自适应策略,也就是自旋的时间是根据上一次自旋的时间动态的改变的。比如上一次我自旋了5此获取到锁资源,下回我就自旋三回,5次获取不到,下回我就自旋十回。

  偏向锁:也是底层,可以理解成一种状态,比如一段代码,没加锁就是无锁状态,加了锁但是只有一个线程执行代码,他是偏向锁,又进来一个线程,两个线程交替进行,偏向锁就成了轻量级锁,多个线程进入开始竞争锁资源,轻量级锁膨胀成重量级锁。可以说所有的锁都有这么一个过程。可以优化禁用偏向锁等。

  轻量级锁:过程同上,贴一下目的

  偏向锁的目的是在某个线程获得锁之后,消除这个线程锁重入(CAS)的开销,看起来让这个线程得到了偏护引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次 CAS 原子指令,而偏向锁只需要在置换ThreadID 的时候依赖一次 CAS 原子指令轻量级锁是为了在线程交替执行同步块时提高性能,而偏向锁则是在只有一个线程执行同步块时进一步提高性能。

六、数据库上的锁

行级锁:也叫排它锁,写sql语句时都会自动加上行级锁,慢、冲突少

表级锁:给表加上锁,有共享读锁、独占写锁(排它锁),快,冲突多。

页级锁:介于行级锁和表级锁中间的锁,速度中庸的锁

 

  

  

原文地址:https://www.cnblogs.com/gushiye/p/13970177.html