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中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4