Synchronized 加锁 This 和Class 的区别!

2025-05-29 0 55

Synchronized 加锁 This 和Class 的区别!

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

synchronized 用法

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

① 修饰普通方法

  1. /**
  2. *synchronized修饰普通方法
  3. */
  4. publicsynchronizedvoidmethod(){
  5. //…….
  6. }

synchronized 修饰普通方法时,被修饰的方法被称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。

② 修饰静态方法

  1. /**
  2. *synchronized修饰静态方法
  3. */
  4. publicstaticsynchronizedvoidstaticMethod(){
  5. //…….
  6. }

synchronized 修饰静态的方法时,其作用的范围是整个方法,作用对象是调用这个类的所有对象。

③ 修饰代码块

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

  1. publicvoidclassMethod()throwsInterruptedException{
  2. //前置代码…
  3. //加锁代码
  4. synchronized(SynchronizedExample.class){
  5. //……
  6. }
  7. //后置代码…
  8. }

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

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

  1. publicvoidclassMethod()throwsInterruptedException{
  2. //前置处理代码…
  3. synchronized(this){
  4. //……
  5. }
  6. //后置处理代码…
  7. }

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

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

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

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

  1. importjava.util.Date;
  2. importjava.util.concurrent.TimeUnit;
  3. publicclassSynchronizedExample{
  4. publicstaticvoidmain(String[]args){
  5. //创建当前类实例
  6. finalSynchronizedExampleexample=newSynchronizedExample();
  7. //创建5个线程执行任务
  8. for(inti=0;i<5;i++){
  9. newThread(newRunnable(){
  10. @Override
  11. publicvoidrun(){
  12. try{
  13. //调用synchronized修饰的class方法
  14. example.classMethod();
  15. }catch(InterruptedExceptione){
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. }
  21. }
  22. /**
  23. *synchronized修饰的class方法
  24. *@throwsInterruptedException
  25. */
  26. publicvoidclassMethod()throwsInterruptedException{
  27. synchronized(SynchronizedExample.class){
  28. System.out.println(String.format("当前执行线程:%s,执行时间:%s",
  29. Thread.currentThread().getName(),newDate()));
  30. TimeUnit.SECONDS.sleep(1);
  31. }
  32. }
  33. }

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

Synchronized 加锁 This 和Class 的区别!

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

2.加锁 class 创建多个实例

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

  1. importjava.util.Date;
  2. importjava.util.concurrent.TimeUnit;
  3. publicclassSynchronizedExample{
  4. publicstaticvoidmain(String[]args){
  5. //创建5个线程执行任务
  6. for(inti=0;i<5;i++){
  7. newThread(newRunnable(){
  8. @Override
  9. publicvoidrun(){
  10. try{
  11. //创建类实例
  12. SynchronizedExampleexample=newSynchronizedExample();
  13. //调用synchronized修饰的class方法
  14. example.classMethod();
  15. }catch(InterruptedExceptione){
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. }
  21. }
  22. /**
  23. *synchronized修饰的class方法
  24. *@throwsInterruptedException
  25. */
  26. publicvoidclassMethod()throwsInterruptedException{
  27. synchronized(SynchronizedExample.class){
  28. System.out.println(String.format("当前执行线程:%s,执行时间:%s",
  29. Thread.currentThread().getName(),newDate()));
  30. TimeUnit.SECONDS.sleep(1);
  31. }
  32. }
  33. }

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

Synchronized 加锁 This 和Class 的区别!

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

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

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

  1. importjava.util.Date;
  2. importjava.util.concurrent.TimeUnit;
  3. publicclassSynchronizedExample{
  4. publicstaticvoidmain(String[]args){
  5. //创建当前类实例
  6. finalSynchronizedExampleexample=newSynchronizedExample();
  7. //创建5个线程执行任务
  8. for(inti=0;i<5;i++){
  9. newThread(newRunnable(){
  10. @Override
  11. publicvoidrun(){
  12. try{
  13. //调用synchronized修饰的this方法
  14. example.thisMethod();
  15. }catch(InterruptedExceptione){
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. }
  21. }
  22. /**
  23. *synchronized修饰的this方法
  24. *@throwsInterruptedException
  25. */
  26. publicvoidthisMethod()throwsInterruptedException{
  27. synchronized(this){
  28. System.out.println(String.format("当前执行线程:%s,执行时间:%s",
  29. Thread.currentThread().getName(),newDate()));
  30. TimeUnit.SECONDS.sleep(1);
  31. }
  32. }
  33. }

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

Synchronized 加锁 This 和Class 的区别!

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

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

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

  1. importjava.util.Date;
  2. importjava.util.concurrent.TimeUnit;
  3. publicclassSynchronizedExample{
  4. publicstaticvoidmain(String[]args){
  5. //创建5个线程执行任务
  6. for(inti=0;i<5;i++){
  7. newThread(newRunnable(){
  8. @Override
  9. publicvoidrun(){
  10. try{
  11. //创建(多个)类实例
  12. SynchronizedExampleexample=newSynchronizedExample();
  13. //调用synchronized修饰的this方法
  14. example.thisMethod();
  15. }catch(InterruptedExceptione){
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. }
  21. }
  22. /**
  23. *synchronized修饰的this方法
  24. *@throwsInterruptedException
  25. */
  26. publicvoidthisMethod()throwsInterruptedException{
  27. synchronized(this){
  28. System.out.println(String.format("当前执行线程:%s,执行时间:%s",
  29. Thread.currentThread().getName(),newDate()));
  30. TimeUnit.SECONDS.sleep(1);
  31. }
  32. }
  33. }

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

Synchronized 加锁 This 和Class 的区别!

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

总结

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

原文链接:https://mp.weixin.qq.com/s/7DTk5CV5FSOsa5fSN_V26w

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Synchronized 加锁 This 和Class 的区别! https://www.kuaiidc.com/109192.html

相关文章

发表评论
暂无评论