Java并发编程必备之Synchronized关键字深入解析

2025-04-03 03:50

本文主要是介绍Java并发编程必备之Synchronized关键字深入解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种...

一、前言

Java多线程编程中,线程安全是非常重要的一个概念。为了防止多个线程同时访问共享资源时出现数据不一致或其他竞态条件问题,Java提供了synchronized关键字和监视器锁(Monitor Lock)机制。这个博客将深入探讨synchronized的原理、使用场景以及与监视器锁的关系。

二、Synchronized关键字pLHhVhbSQE

synchronized是Java中的一个关键字,用于在多线程环境中控制对共享资源的访问。当一个线程执行synchronized修饰的方法或代码块时,其他线程将无法访问相同的资源,直到当前线程释放资源锁。

2.1 Synchronized的特性

1. 互斥

Synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待。

• 进入 synchronized 修饰的代码块, 相当于 加锁
• 退出 synchronized 修饰的代码块, 相当于 解锁

   synchronized (locker){
                for (int i = 0; i < 5000; i++) {
                    count++;
                }
            }

Java并发编程必备之Synchronized关键字深入解析

synchronized用的锁是存在Java对象头里的。

Java并发编程必备之Synchronized关键字深入解析

可以粗略理解成, 每个对象在内存中存储的时候, 都存有一块内存表示当前的 “锁定” 状态(类似于厕所
的 “有人/无人”)。
如果当前是 “无人” 状态, 那么就可以使用, 使用时需要设为 “有人” 状态。
如果当前是 “有人” 状态, 那么其他人无法使用, 只能排队。

Java并发编程必备之Synchronized关键字深入解析

理解 “阻塞等待”。
针对每⼀把锁, 操作系统内部都维护了⼀个等待队列. 当这个锁被某个线程占有的时候, 其他线程尝试
进行加锁, 就加不上了, 就会阻塞等待, ⼀直等到之前的线程解锁之后, 由操作系统唤醒⼀个新的线程,
再来获取到这个锁.

注意:

• 上一个线程解锁之后, 下一个线程并不是立即就能获取到锁。而是要靠操作系统来 “唤醒”. 这也就
是操作系统线程调度的一部分工作。
• 假设有 A B C 三个线程, 线程 A 先获取到锁, 然后 B 尝试获取锁, 然后 C 再尝试获取锁, 此时 B 和 C
都在阻塞队列中排队等待.。但是当 A 释放锁之后, 虽然 B 比 C 先来的, 但是 B 不一定就能获取到锁,
而是和 C 重新竞争, 并不遵守先来后到的规则。
synchronized的底层是使用操作系统的mutex lock实现的。

2. 可重入

synchronized 同步块对同⼀条线程来说是可重入的,不会出现自己把自己锁死的问题。

理解 “把自己锁死”

⼀个线程没有释放锁, 然后又尝试再次加锁。
第⼀次加锁, 加锁成功
lock();
第⼆次加锁, 锁已经被占用, 阻塞等待
lock();
按照之前对于锁的设定, 第二次加锁的时候, 就会阻塞等待. 直到第一次的锁被释放, 才能获取到第二
个锁.。但是释放第⼀个锁也是由该线程来完成, 结果这个线程已经躺平了, 啥都不想干了, 也就无法进行解锁操作. 这时候就会死锁。

Java并发编程必备之Synchronized关键字深入解析

Java 中的 synchronized可重⼊锁, 因此没有上面的问题。

for (int i = 0; i < 50000; i++) {
 synchronized (locker) {
 synchronized (locker) {
             count++;
           }
      }
}

在可重入锁的内部, 包含了 “线程持有者” 和 “计数器” 两个信息。
• 如果某个线程加锁的时候, 发现锁已经被人占用, 但是恰好占用的正是自己, 那么仍然可以继续获取到锁, 并让计数器自增。
• 解锁的时候计数器递减为 php0 的时候, 才真正释放锁. (才能被别的线程获取到)

三、synchronized 的使用示例

synchronized 本质上要修改指定对象的 “对象头”。从使用角度来看,synchronized 也势必要搭配⼀个具体的对象来使用。

3.1 修饰代码块: 明确指定锁哪个对象

1.锁任意对象

public class Synchrinized1 {
    private static int count;
    public static void main(String[] args) {
        Object locker=new Object();
        Thread t1=new Thread(()->{
            for (int i = 0; i <10000 ; i++) {
                synchronized (locker){
                    count++;//锁任意对象
                }
            }
        });
    }
}

2.锁当前对象

public class Synchrinized1 {
    private static int count;
    public static void main(String[] args) {
        Object locker=new Object();
        Thread t1=new Thread(()->{
            for (int i = 0; i <10000 ; i++) {
                synchronized (this){
                    count++;//锁当前对象
                }
            }
        });
    }
}

3.2直接修饰普通方法

pujavascriptblic class Synchronized2{
    public int count=0;
    synchronized public void methond(){
        count++;
    }
}

3.3 修饰静态方法

public class Synchronized{
    public static int count=0;
   public static synchronized void methon(){
        count++;
    }
}

四 、监视器锁(Monitor Lock)

Monitor Lock(监视器锁)是一种高级同步机制,底层实现了synchronized关键字的功能。每个对象都关联一个监视器锁,当线程进入synchronized块时,线程会获取该对象的监视器锁。

4.1 监视器锁的特点

  • 互斥性:同一时间只有一个线程可以持有监视器锁。
  • 可重入性:同一线程可以多次获取已持有的监视器锁。
  • 锁升级:从未锁定状态偏向锁,再到轻量级锁,最终升级为重量级锁

4.2 Synchronized的底层实现

synchronized关键字的实现依赖于JVM,而JVM底层使用了监视器锁(Monitor Lock)来实现线程的同步。

当线程执行synchronized代码时,JVM会检查是否已经获得了监视器锁:

  • 如果未加锁,当前线程会尝试获取锁。
  • 如果已加锁,当前线程将被阻塞,直到锁被释放。

4.3 onitor Lock的状态

一个监视器锁有以下四种状态:

  • 未锁定状态:任何线程都可以竞争锁。
  • 偏向锁状态:只允许一个线程持有锁,减少竞争。
  • 轻量级锁状态:多个线程竞争锁,但未发生旋转或阻塞。
  • 重量级锁状态:线程竞争激烈,锁被线程阻塞等待。

4.4 Synchronized与ReentrantLock的比较

4.5 常见问题及解决方案

1. 避免过度同步

过度http://www.chinasem.cn同步会降低并发性能,应尽量缩小同步范围。

2. 避免死锁

死锁是由于多个线程互相持有对方资源而导致的。可以通过如下方式避免:

  • 按顺序加锁:对多个锁的加锁顺序进行统一。
  • 避免嵌套锁:减少嵌套使用锁的场景。

3. 数据一致性问题

在单例模式或共享变量的场景中,必须确保所有修改共享资源的操作都在同步块内。

五、总结

通过本文,我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性。文章详细介绍了Synchronized的三种使用方式:修饰代码块、修饰普通方法和修饰静态方法。同时,我们还解析了监视器锁(Monitor Lock)的底层实现,以及SynchronizedReentrantLock的对比。最后,文章总结了并发编程中常见问题的解决方案,如避免过度同步、防止死锁和保持数据一致性。本文旨在帮助开发者更好地理解和使用Synchronized,从而编写出高效、安全的并发程序。

到此这篇关于Java并发编程必备之Synchronized关键字深入解析的文章就介绍到这了,更多相关Java Synchronized关键字内容请搜索China编程(whttp://www.chinasem.cnww.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Java并发编程必备之Synchronized关键字深入解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154068

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义