您现在的位置是:亿华云 > IT科技类资讯
synchronized 加锁 this 和 class 的区别!
亿华云2025-10-09 01:21:31【IT科技类资讯】0人已围观
简介synchronized 是 Java 语言中处理并发问题的一种常用手段,它也被我们亲切的称之为“Java 内置锁”,由此可见其地位之高。然而 synchronized 却有着多种用法,当它修饰不同对
synchronized 是加锁 Java 语言中处理并发问题的一种常用手段,它也被我们亲切的加锁称之为“Java 内置锁”,由此可见其地位之高。加锁然而 synchronized 却有着多种用法,加锁当它修饰不同对象时,加锁其意义也是加锁不同的,下面我们一起来看。加锁
synchronized 用法
synchronized 可以用来修饰普通方法、加锁静态方法和代码块。加锁
① 修饰普通方法
/** * synchronized 修饰普通方法 */ public synchronized void method() { // ....... }当 synchronized 修饰普通方法时,加锁被修饰的加锁方法被称为同步方法,其作用范围是加锁整个方法,作用的加锁对象是调用这个方法的对象。
② 修饰静态方法
/** * synchronized 修饰静态方法 */ public static synchronized void staticMethod() { // ....... }当 synchronized 修饰静态的加锁方法时,其作用的加锁范围是整个方法,作用对象是调用这个类的所有对象。
③ 修饰代码块
为了减少锁的粒度,我们可以选择在一个方法中的b2b信息网某个部分使用 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() { @Override public 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() { @Override public 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() { @Override public 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() { @Override public 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 时,只有同一个对象会使用同一把锁,不同对象之间的锁是不同的。
很赞哦!(11)
相关文章
- 互联网其实拼的也是人脉,域名投资也是一个时效性很强的东西,一个不起眼的消息就会引起整个域名投资市场的动荡,因此拓宽自己的人脉圈,完善自己的信息获取渠道,让自己能够掌握更为多样化的信息,这样才更有助于自己的域名投资。
- 细谈Dotnet洋葱架构实践
- 掌握它才说明你真正懂Elasticsearch
- 值得推荐的十种PHP测试框架
- 其次,一般域名注册有一个获取密码的按钮,域名注册商点击后会向您发送密码。在得到域名注册商发送的密码后,将其传输到域名服务提供商网站,然后输入密码,此时域名呈现申请状态。提交申请后,原注册人通常会向您发送一封电子邮件,询问您是否同意转让。此时,您只需点击同意转移按钮,域名注册商就可以成功转移。
- RocketMQ基础概念剖析&源码解析
- 陈天奇最新研究:递归模型编译器CORTEX
- Python高能小技巧:了解bytes与str的区别
- Status、Creation Date、Expiration Date
- LeetCode题解之重建二叉树