中国可信网站查询,想用自己电脑做服务器做个网站吗,网站建设的网络公司,客户做网站要退款(给ImportNew加星标#xff0c;提高Java技能)转自#xff1a;悟空聊架本篇主要内容如下#xff1a;本篇文章已收纳到我的 Java 在线文档、 Github。我的 SpringCloud 实战项目持续更新中。帮你总结好的锁#xff1a;序号锁名称应用1乐观锁CAS2悲观锁synchronized、vector、… (给ImportNew加星标提高Java技能)转自悟空聊架本篇主要内容如下本篇文章已收纳到我的 Java 在线文档、 Github。我的 SpringCloud 实战项目持续更新中。帮你总结好的锁序号锁名称应用1乐观锁CAS2悲观锁synchronized、vector、hashtable3自旋锁CAS4可重入锁synchronized、Reentrantlock、Lock5读写锁ReentrantReadWriteLockCopyOnWriteArrayList、CopyOnWriteArraySet6公平锁Reentrantlock(true)7非公平锁synchronized、reentrantlock(false)8共享锁ReentrantReadWriteLock中读锁9独占锁synchronized、vector、hashtable、ReentrantReadWriteLock中写锁10重量级锁synchronized11轻量级锁锁优化技术12偏向锁锁优化技术13分段锁concurrentHashMap14互斥锁synchronized15同步锁synchronized16死锁相互请求对方的资源17锁粗化锁优化技术18锁消除锁优化技术1. 乐观锁乐观锁是一种乐观思想。假定当前环境是读多写少遇到并发写的概率比较低读数据时认为别的线程不会正在进行修改(所以没有上锁)。写数据时判断当前 与期望值是否相同如果相同则进行更新(更新期间加锁保证是原子性的)。Java 中的乐观锁CAS。比较并替换比较当前值(主内存中的值)与预期值(当前线程中的值主内存中值的一份拷贝)是否一样一样则更新否则继续进行 CAS 操作。如上图所示可以同时进行读操作读的时候其他线程不能进行写操作。2. 悲观锁悲观锁是一种悲观思想。认为写多读少遇到并发写的可能性高每次去拿数据的时候都认为其他线程会修改所以每次读写数据都会认为其他线程会修改所以每次读写数据时都会上锁。其他线程想要读写这个数据时会被这个线程 block直到这个线程释放锁然后其他线程获取到锁。Java 中的悲观锁synchronized 修饰的方法和方法块、ReentrantLock。如上图所示只能有一个线程进行读操作或者写操作其他线程的读写操作均不能进行。3. 自旋锁自旋锁是一种技术为了让线程等待我们只须让线程执行一个忙循环(自旋)。现在绝大多数的个人电脑和服务器都是多路(核)处理器系统如果物理机器有一个以上的处理器或者处理器核心能让两个或以上的线程同时并行执行就可以让后面请求锁的那个线程“稍等一会”但不放弃处理器的执行时间看看持有锁的线程是否很快就会释放锁。自旋锁的优点避免了线程切换的开销。挂起线程和恢复线程的操作都需要转入内核态中完成这些操作给 Java 虚拟机的并发性能带来了很大的压力。自旋锁的缺点占用处理器的时间如果占用的时间很长会白白消耗处理器资源而不会做任何有价值的工作带来性能的浪费。因此自旋等待的时间必须有一定的限度如果自旋超过了限定的次数仍然没有成功获得锁就应当使用传统的方式去挂起线程。自旋次数默认值10次。可以使用参数 -XX:PreBlockSpin 来自行更改。自适应自旋自适应意味着自旋的时间不再是固定的而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。有了自适应自旋随着程序运行时间的增长及性能监控信息的不断完善虚拟机对程序锁的状态预测就会越来越精准。Java 中的自旋锁CAS。操作中的比较操作失败后的自旋等待。4. 可重入锁(递归锁)可重入锁是一种技术任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞。可重入锁的原理通过组合自定义同步器来实现锁的获取与释放。再次获取锁识别获取锁的线程是否为当前占据锁的线程如果是则再次成功获取。获取锁后进行计数自增释放锁释放锁时进行计数自减。Java 中的可重入锁ReentrantLock、synchronized 修饰的方法或代码段。可重入锁的作用避免死锁。面试题1可重入锁如果加了两把但是只释放了一把会出现什么问题答程序卡死线程不能出来也就是说我们申请了几把锁就需要释放几把锁。面试题2如果只加了一把锁释放两次会出现什么问题答会报错抛出 java.lang.IllegalMonitorStateException。5. 读写锁读写锁是一种技术通过 ReentrantReadWriteLock 类来实现。为了提高性能 Java 提供了读写锁。在读的地方使用读锁在写的地方使用写锁灵活控制。如果没有写锁的情况下读是无阻塞的。在一定程度上提高了程序的执行效率。读写锁分为读锁和写锁多个读锁不互斥读锁与写锁互斥这是由 JVM 自己控制的。读锁允许多个线程获取读锁同时访问同一个资源。写锁只允许一个线程获取写锁不允许同时访问同一个资源。如何使用/*** 创建一个读写锁* 它是一个读写融为一体的锁在使用的时候需要转换*/private ReentrantReadWriteLock rwLock new ReentrantReadWriteLock();获取读锁和释放读锁// 获取读锁rwLock.readLock().lock();// 释放读锁rwLock.readLock().unlock();获取写锁和释放写锁// 创建一个写锁rwLock.writeLock().lock();// 写锁 释放rwLock.writeLock().unlock();Java中的读写锁ReentrantReadWriteLock。6. 公平锁公平锁是一种思想多个线程按照申请锁的顺序来获取锁。在并发环境中每个线程会先查看此锁维护的等待队列如果当前等待队列为空则占有锁如果等待队列不为空则加入到等待队列的末尾按照 FIFO 的原则从队列中拿到线程然后占有锁。7. 非公平锁非公平锁是一种思想线程尝试获取锁如果获取不到则再采用公平锁的方式。多个线程获取锁的顺序不是按照先到先得的顺序有可能后申请锁的线程比先申请的线程优先获取锁。优点非公平锁的性能高于公平锁。缺点有可能造成线程饥饿(某个线程很长一段时间获取不到锁)。Java 中的非公平锁synchronized 是非公平锁。ReentrantLock 通过构造函数指定该锁是公平的还是非公平的默认是非公平的。8. 共享锁共享锁是一种思想可以有多个线程获取读锁以共享的方式持有锁。和乐观锁、读写锁同义。Java 中用到的共享锁ReentrantReadWriteLock。9. 独占锁独占锁是一种思想只能有一个线程获取锁以独占的方式持有锁。和悲观锁、互斥锁同义。Java 中用到的独占锁synchronized、ReentrantLock。10. 重量级锁重量级锁是一种称谓synchronized 是通过对象内部的一个叫做监视器锁(monitor)来实现的。监视器锁本身依赖底层的操作系统的 Mutex Lock 来实现。操作系统实现线程的切换需要从用户态切换到核心态成本非常高。这种依赖于操作系统 Mutex Lock来实现的锁称为重量级锁。为了优化 synchonized 引入了轻量级锁偏向锁。Java 中的重量级锁synchronized。11. 轻量级锁轻量级锁是 JDK6 时加入的一种锁优化机制轻量级锁是在无竞争的情况下使用 CAS 操作去消除同步使用的互斥量。轻量级是相对于使用操作系统互斥量来实现的重量级锁而言的。轻量级锁在没有多线程竞争的前提下减少传统的重量级锁使用操作系统互斥量产生的性能消耗。如果出现两条以上的线程争用同一个锁的情况那轻量级锁将不会有效必须膨胀为重量级锁。优点如果没有竞争通过 CAS 操作成功避免了使用互斥量的开销。缺点如果存在竞争除了互斥量本身的开销外还额外产生了 CAS 操作的开销因此在有竞争的情况下轻量级锁比传统的重量级锁更慢。12. 偏向锁偏向锁是 JDK6 时加入的一种锁优化机制在无竞争的情况下把整个同步都消除掉连 CAS 操作都不去做了。偏是指偏心它的意思是这个锁会偏向于第一个获得它的线程如果在接下来的执行过程中该锁一直没有被其他的线程获取则持有偏向锁的线程将永远不需要再进行同步。持有偏向锁的线程以后每次进入这个锁相关的同步块时虚拟机都可以不再进行任何同步操作(例如加锁、解锁及对 Mark Word 的更新操作等)。优点把整个同步都消除掉连 CAS 操作都不去做了优于轻量级锁。缺点如果程序中大多数的锁都总是被多个不同的线程访问那偏向锁就是多余的。13. 分段锁分段锁是一种机制最好的例子来说明分段锁是 ConcurrentHashMap。ConcurrentHashMap 原理它内部细分了若干个小的 HashMap称之为段(Segment)。默认情况下一个 ConcurrentHashMap 被进一步细分为 16 个段既就是锁的并发度。如果需要在 ConcurrentHashMap 添加一项 key-value并不是将整个 HashMap 加锁而是首先根据 hashcode 得到该 key-value 应该存放在哪个段中然后对该段加锁并完成 put 操作。在多线程环境中如果多个线程同时进行 put 操作只要被加入的 key-value 不存放在同一个段中则线程间可以做到真正的并行。线程安全ConcurrentHashMap 是一个 Segment 数组 Segment 通过继承ReentrantLock 来进行加锁所以每次需要加锁的操作锁住的是一个 segment这样只要保证每个 Segment 是线程安全的也就实现了全局的线程安全。14. 互斥锁互斥锁与悲观锁、独占锁同义表示某个资源只能被一个线程访问其他线程不能访问。读读互斥读写互斥写读互斥写写互斥。Java 中的同步锁synchronized。15. 同步锁同步锁与互斥锁同义表示并发执行的多个线程在同一时间内只允许一个线程访问共享数据。Java中的同步锁synchronized。16. 死锁死锁是一种现象如线程 A 持有资源 x线程 B 持有资源 y线程 A 等待线程 B 释放资源 y线程 B 等待线程 A 释放资源 x两个线程都不释放自己持有的资源则两个线程都获取不到对方的资源就会造成死锁。Java 中的死锁不能自行打破。所以线程死锁后线程不能进行响应。所以一定要注意程序的并发场景避免造成死锁。17. 锁粗化锁粗化是一种优化技术如果一系列的连续操作都对同一个对象反复加锁和解锁甚至加锁操作都是出现在循环体体之中就算真的没有线程竞争频繁地进行互斥同步操作将会导致不必要的性能损耗。所以就采取了一种方案把加锁的范围扩展(粗化)到整个操作序列的外部这样加锁解锁的频率就会大大降低从而减少了性能损耗。18. 锁消除锁消除是一种优化技术就是把锁干掉。当 Java 虚拟机运行时发现有些共享数据不会被线程竞争时就可以进行锁消除。那如何判断共享数据不会被线程竞争利用逃逸分析技术分析对象的作用域如果对象在 A 方法中定义后被作为参数传递到B方法中则称为方法逃逸如果被其他线程访问则称为线程逃逸。在堆上的某个数据不会逃逸出去被其他线程访问到就可以把它当作栈上数据对待认为它是线程私有的同步加锁就不需要了。19. synchronizedsynchronized 是 Java中的关键字用来修饰方法、对象实例。属于独占锁、悲观锁、可重入锁、非公平锁。作用于实例方法时锁住的是对象的实例(this)当作用于静态方法时锁住的是类(class)。相当于类的一个全局锁 会锁所有调用该方法的线程synchronized 作用于一个非 null 的对象实例时锁住的是所有以该对象为锁的代码块。它有多个队列当多个线程一起访问某个对象监视器的时候对象监视器会将这些线程存储在不同的容器中。每个对象都有个 monitor 对象 加锁就是在竞争 monitor 对象。代码块加锁是在代码块前后分别加上 monitorenter 和 monitorexit 指令来实现的方法加锁是通过一个标记位来判断的。20. Lock 和 synchronized 的区别Lock 是 Java 中的接口可重入锁、悲观锁、独占锁、互斥锁、同步锁。Lock 需要手动获取锁和释放锁。就好比自动挡和手动挡的区别Lock 是一个接口而 synchronized 是 Java 中的关键字。synchronized 是 Java 语言内置的实现synchronized 在发生异常时会自动释放线程占有的锁因此不会导致死锁现象发生而 Lock 在发生异常时如果没有主动通过 unLock() 去释放锁则很可能造成死锁现象因此使用 Lock 时需要在 finally 块中释放锁Lock 可以让等待锁的线程响应中断而 synchronized 却不行。使用 synchronized 时等待的线程会一直等待下去不能够响应中断通过 Lock 可以知道有没有成功获取锁而 synchronized 却无法办到Lock 可以通过实现读写锁提高多个线程进行读操作的效率。synchronized 的优势足够清晰简单只需要基础的同步功能时用 synchronizedLock 应该确保在 finally 块中释放锁。如果使用 synchronizedJVM确保即使出现异常锁也能被自动释放使用 Lock 时Java 虚拟机很难得知哪些锁对象是由特定线程锁持有的。21. ReentrantLock 和 synchronized 的区别ReentrantLock 是 Java 中的类继承了 Lock 类可重入锁、悲观锁、独占锁、互斥锁、同步锁。划重点相同点主要解决共享变量如何安全访问的问题都是可重入锁也叫做递归锁同一线程可以多次获得同一个锁保证了线程安全的两大特性可见性、原子性。不同点ReentrantLock 就像手动汽车需要显示的调用 lock 和 unlock 方法 synchronized 隐式获得释放锁ReentrantLock 可响应中断 synchronized 是不可以响应中断的ReentrantLock 为处理锁的不可用性提供了更高的灵活性ReentrantLock 是 API 级别的 synchronized 是 JVM 级别的ReentrantLock 可以实现公平锁、非公平锁默认非公平锁。synchronized 是非公平锁且不可更改ReentrantLock 通过 Condition 可以绑定多个条件。推荐阅读 点击标题可跳转Redis 分布式锁的正确实现方式( Java 版 )为什么 ConcurrentHashMap 的读操作不需要加锁一句话撸完重量级锁、自旋锁、轻量级锁、偏向锁、悲观、乐观锁等各种锁 ---- 不看后悔系列看完本文有收获请转发分享给更多人关注「ImportNew」提升Java技能好文章我在看❤️