synchronized 加锁 this 和 class 的区别
创始人
2025-05-31 19:48:27
0

synchronized 是 Java 语言中处理并发问题的一种常用手段,它也被我们亲切的称之为“Java 内置锁”,由此可见其地位之高。然而 synchronized 却有着多种用法,当它修饰不同对象时,其意义也是不同的,下面我们一起来看。 ​


synchronized 用法

synchronized 可以用来修饰普通方法、静态方法和代码块。 

① 修饰非静态方法

/*** synchronized 修饰普通方法*/
public synchronized void method() {// .......
} 

当 synchronized 修饰普通方法时,被修饰的方法被称为同步方法,其作用范围是整个方法

对于非静态方法,同一个实例的线程访问会被拦截,非同一实例可以同时访问。 

② 修饰静态方法

/*** synchronized 修饰静态方法*/
public static synchronized void staticMethod() {// .......
} 

当 synchronized 修饰静态的方法时,其作用的范围是整个方法

只要采用类锁,就会拦截所有线程,不论是不是同一实列,只能让一个线程访问

③ 修饰代码块

为了减少锁的粒度,我们可以选择在一个方法中的某个部分使用 synchronized 来修饰(一段代码块),从而实现对一个方法中的部分代码进行加锁,实现代码如下:

public void classMethod() throws InterruptedException {// 前置代码...// 加锁代码synchronized (SynchronizedExample.class) {// ......}// 后置代码...
} 

以上代码在执行时,被修饰的代码块称为同步语句块,其作用范围是大括号“{}”括起来的代码块,作用的对象是调用这个代码块的对象。 ​

但以上代码,除了可以加锁 class 之外,还可以加锁 this,具体示例如下:

public void classMethod() throws InterruptedException {// 前置处理代码...synchronized (this) {// ......}// 后置处理代码...
} 

那问题来了,使用 synchronized 加锁 this 和 class 的区别是什么?不都是加锁同一个类吗? ​

答案还真不是,加锁 this 和 class 区别还是很大的。下面我们通过以下 4 个示例,来看二者之间的区别。


1、加锁 class 共享一个类实例

首先,我们创建 5 个线程,调用同一个对象下 synchronized 加锁的 class 代码,具体示例如下:

import java.util.Date;
import java.util.concurrent.TimeUnit;public class SynchronizedExample {public static void main(String[] args) {// 创建当前类实例final SynchronizedExample example = new SynchronizedExample();// 创建 5 个线程执行任务for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {// 调用 synchronized 修饰的 class 方法example.classMethod();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}/*** synchronized 修饰的 class 方法* @throws InterruptedException*/public void classMethod() throws InterruptedException {synchronized (SynchronizedExample.class) {System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(), new Date()));TimeUnit.SECONDS.sleep(1);}}
} 

以上程序的执行结果如下:

从上述结果可以看出,这 5 个线程共享的是同一把锁

2、加锁 class 创建多个实例 

接下来,我们创建 5 个线程,调用不同对象下 synchronized 加锁的 class 代码,具体示例如下:

import java.util.Date;
import java.util.concurrent.TimeUnit;public class SynchronizedExample {public static void main(String[] args) {// 创建 5 个线程执行任务for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {// 创建类实例SynchronizedExample example = new SynchronizedExample();// 调用 synchronized 修饰的 class 方法example.classMethod();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}/*** synchronized 修饰的 class 方法* @throws InterruptedException*/public void classMethod() throws InterruptedException {synchronized (SynchronizedExample.class) {System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(), new Date()));TimeUnit.SECONDS.sleep(1);}}
} 

以上程序的执行结果如下:

 从上述结果可以看出,虽然是不同的对象,但它们使用的仍然是同一把锁

3、加锁 this 共享一个类实例

接下来,我们创建 5 个线程,调用 synchronized 加锁 this 的示例。首先我们这 5 个线程调用同一个对象的加锁方法,示例代码如下:

import java.util.Date;
import java.util.concurrent.TimeUnit;public class SynchronizedExample {public static void main(String[] args) {// 创建当前类实例final SynchronizedExample example = new SynchronizedExample();// 创建 5 个线程执行任务for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {// 调用 synchronized 修饰的 this 方法example.thisMethod();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}/*** synchronized 修饰的 this 方法* @throws InterruptedException*/public void thisMethod() throws InterruptedException {synchronized (this) {System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(), new Date()));TimeUnit.SECONDS.sleep(1);}}
} 

以上程序的执行结果如下:

从上述结果可以看出,以上线程使用的都是同一把锁

4、加锁 this 创建多个类实例

最后一个示例最为特殊,我们使用 synchronized 加锁 this,让这 5 个线程调用各自创建对象的方法,具体示例如下:

import java.util.Date;
import java.util.concurrent.TimeUnit;public class SynchronizedExample {public static void main(String[] args) {// 创建 5 个线程执行任务for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {try {// 创建(多个)类实例SynchronizedExample example = new SynchronizedExample();// 调用 synchronized 修饰的 this 方法example.thisMethod();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}/*** synchronized 修饰的 this 方法* @throws InterruptedException*/public void thisMethod() throws InterruptedException {synchronized (this) {System.out.println(String.format("当前执行线程:%s,执行时间:%s",Thread.currentThread().getName(), new Date()));TimeUnit.SECONDS.sleep(1);}}
} 

 以上程序的执行结果如下:

从上述结果可以看出,当使用 synchronized 加锁 this 时,如果线程调用的不是同一个对象,那么这些线程之间使用的锁都是自己独立的锁,这个结果就和 synchronized 加锁 class 的结果完全不同了。 ​


总结 

通过以上 4 个示例我们可以得出结论,当使用 synchronized 加锁 class 时,无论共享一个对象还是创建多个对象,它们用的都是同一把锁,而使用 synchronized 加锁 this 时,只有同一个对象会使用同一把锁,不同对象之间的锁是不同的。 ​

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
JAVA多线程知识整理 Java多线程基础 线程的创建和启动 继承Thread类来创建并启动 自定义Thread类的子类&#...
【洛谷 P1090】[NOIP... [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G ...
国民技术LPUART介绍 低功耗通用异步接收器(LPUART) 简介 低功耗通用异步收发器...
城乡供水一体化平台-助力乡村振... 城乡供水一体化管理系统建设方案 城乡供水一体化管理系统是运用云计算、大数据等信息化手段࿰...
程序的循环结构和random库...   第三个参数就是步长     引入文件时记得指明字符格式,否则读入不了 ...
中国版ChatGPT在哪些方面... 目录 一、中国巨大的市场需求 二、中国企业加速创新 三、中国的人工智能发展 四、企业愿景的推进 五、...
报名开启 | 共赴一场 Flu... 2023 年 1 月 25 日,Flutter Forward 大会在肯尼亚首都内罗毕...
汇编00-MASM 和 Vis... Qt源码解析 索引 汇编逆向--- MASM 和 Visual Studio入门 前提知识ÿ...
【简陋Web应用3】实现人脸比... 文章目录🍉 前情提要🌷 效果演示🥝 实现过程1. u...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
windows安装JDK步骤 一、 下载JDK安装包 下载地址:https://www.oracle.com/jav...
分治法实现合并排序(归并排序)... 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨...
在linux上安装配置node... 目录前言1,关于nodejs2,配置环境变量3,总结 前言...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
Linux内核进程管理并发同步... 并发同步并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理...
opencv学习-HOG LO... 目录1. HOG(Histogram of Oriented Gradients,方向梯度直方图)1...
EEG微状态的功能意义 导读大脑的瞬时全局功能状态反映在其电场结构上。聚类分析方法一致地提取了四种头表面脑电场结构ÿ...
【Unity 手写PBR】Bu... 写在前面 前期积累: GAMES101作业7提高-实现微表面模型你需要了解的知识 【技...