【Java八股锁机制的认识】synchronized和reentrantlock区分,锁升级机制

synchronized和reentrantlock及其应用场景?

synchronized 是什么

synchronized 是 Java 提供的 内置锁机制。

核心一句话:

保证同一时间只有一个线程执行某段代码。

例如

同时调用三个线程:线程A,线程B,线程C

有synchronized的存在使得三个线程可以

A执行完

B再执行

C最后执行

避免了线程安全问题(A B C 同时执行)

synchronized 的本质

synchronized 是锁,更是对象监视器锁(Monitor Lock)

用synchronized锁住了obj类,当有线程进入到obj类中,就会获取到obj的锁。如果别人已经拿走了锁,就必须进行等待。

synchronized 的三种用法

  1. 锁普通方法
java 复制代码
public synchronized void method(){
}

锁的是:this对象

  1. 锁代码块
java 复制代码
synchronized(obj){
}

锁的是:obj对象

  1. 锁静态方法
java 复制代码
public static synchronized void method(){
}

锁的是:Class对象

ReentrantLock 是什么

ReentrantLock 是 Java并发包提供的一种锁

相比synchronized更高级

使用方法:

java 复制代码
Lock lock = new ReentrantLock();

lock.lock();
try{
    // 临界区
}finally{
    lock.unlock();
}

流程:

加锁

执行

释放锁

为什么叫 Reentrant(可重入)

可重入表示:

同一个线程可以多次获得同一把锁。

举个例子:

methodA()

methodB()

两个方法都加锁:lock

同一个线程进入 methodA 后:还能进入 methodB

不会死锁。

注意:

synchronized 也是可重入锁

所以:

两者都是可重入锁

ReentrantLock 比 synchronized好在哪?

1 可以手动控制锁

synchronized

自动加锁 自动释放

ReentrantLock

手动 lock() 手动 unlock()

2 可以尝试获取锁

java 复制代码
lock.tryLock()

说明:如果拿不到锁,就直接返回。

而synchronized

只能等待。

3 可以设置公平锁

java 复制代码
new ReentrantLock(true)

公平锁:

先来先得

synchronized:

不支持公平锁

4 可以中断等待线程

java 复制代码
lock.lockInterruptibly()

线程可以:被中断

synchronized 不支持。

真实应用场景

简单同步

用synchronized

比如:

计数器 简单资源保护

java 复制代码
public synchronized void add(){
    count++;
}

复杂锁控制

用ReentrantLock

比如:

需要尝试获取锁

需要超时

需要公平锁

java 复制代码
if(lock.tryLock()){
   // 执行
}

高并发组件

用ReentrantLock

比如:

线程池

并发容器

阻塞队列

总结表

特性 synchronized ReentrantLock
类型 JVM关键字 Java类
加锁方式 自动 手动
释放锁 自动 必须unlock
可重入 支持 支持
公平锁 不支持 支持
tryLock 不支持 支持
中断锁 不支持 支持
复杂控制

syncronized锁升级的过程

先理解为什么需要锁升级

因为在早期JDK版本,syncronized性能很差,因为他使用的是操作系统级别的互斥锁(Mutex),一旦线程竞争锁,就会发生

线程阻塞

线程唤醒

所以在JDK1.6版本之后,出现了优化:

锁会根据竞争情况逐渐升级。

这就是锁升级的由来。

锁升级的整体过程

升级过程:

无锁

偏向锁

轻量级锁

重量级锁

一句话理解:竞争越激烈,锁越重。

第一阶段无锁状态

第二阶段偏向锁

第一个线程访问到

java 复制代码
synchronized(obj){
}

JVM会认为只有一个线程会访问,于是进入偏向锁

偏向锁的含义:

锁偏向某个线程

对象头会记录:

线程ID

之后如果线程A再进入

不需要加锁

不需要CAS

直接执行

性能接近于:无锁

第三阶段:轻量级锁

此时如果另一个线程来了 :线程B

线程B尝试获取锁

此时JVM发现:锁已经偏向线程A

于是:偏向锁失效

升级为:轻量级锁

轻量级锁的核心思想是:

自旋

线程不会立即阻塞,而是:

循环尝试获取锁

例如:

while(锁没释放){

再试一次

}

这样可以避免:

线程阻塞

线程唤醒

性能比重量级锁好很多。

第四阶段:重量级锁

如果线程越来越多:

线程A

线程B

线程C

线程D

此时自旋会消耗大量CPU。

JVM就会判断

竞争过于激烈,将锁升级成重量级锁

特点:

线程会被阻塞

进入:

操作系统的Mutex锁

流程变为:

线程A执行

线程B阻塞

线程C阻塞

等线程A释放锁后:

操作系统唤醒其他线程

锁升级流程图

线程访问同步代码

无锁

偏向锁

(单线程访问)

轻量级锁

(少量竞争)

重量级锁

(激烈竞争)

存在的意义

总结:锁升级,就是为了

减少线程阻塞带来的性能开销。

发明的产物

相关推荐
Fruit_Caller1 小时前
GmSSL 编译与 Qt 项目集成问题排查记录(-lssl-1_1-x64 -lcrypto-1_1-x64)
开发语言·qt
free-elcmacom1 小时前
C++三种参数传递方式:从交换函数看值、指针与引用的区别
开发语言·c++
bubiyoushang8882 小时前
基于PSO的列车速度优化MATLAB实现
开发语言·人工智能·matlab
Barkamin2 小时前
(有头)链表的实现(Java)
java·数据结构·链表
乐hh2 小时前
Hadoop 3.3.5 + Flink 1.15.3 集群完整部署手册(3节点标准版)
java·大数据·hadoop·hdfs·zookeeper·flink·yarn
SunnyDays10112 小时前
如何使用 Java 实现自动删除 Word 文档中的空白页或指定页
java·删除 word 文档空白页·删除 word 文档页面
༄天M宇ༀ2 小时前
E10: e-builder 低代码构建平台接口管理(E9建模版)
java·前端·spring·servlet·reactjs
曹牧2 小时前
C#:线程中实现延时等待
开发语言·c#
蜜獾云2 小时前
java 异步编程
java·开发语言