synchronized的应用和实现原理

7 篇文章 0 订阅

1.synchronized的应用

关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性

利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。具体表现为以下3种形式。

  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的Class对象。
  • 对于同步方法块,锁是Synchonized括号里配置的对象。

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

1.1对于普通同步方法,锁是当前实例对象

public class SynchronizedDemo {

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo=new SynchronizedDemo();
        synchronizedDemo.methodA();   //锁是synchronizedDemo对象
        synchronizedDemo.methodB();   //锁是synchronizedDemo对象

        SynchronizedDemo synchronizedDemo1=new SynchronizedDemo();
        synchronizedDemo1.methodA();   //锁是synchronizedDemo1对象
        synchronizedDemo1.methodB();   //锁是synchronizedDemo1对象
        
        
    }

    public synchronized void methodA(){

    }

    public synchronized void methodB(){

    }
}

1.2对于静态同步方法,锁是当前类的Class对象

public class SynchronizedDemo {

    public static void main(String[] args) {
        SynchronizedDemo.methodC();   //锁是当前的Class对象
        SynchronizedDemo.methodD();   //锁是当前的Class对象
    }

    public static synchronized void methodC(){

    }

    public static synchronized void methodD(){

    }

}

1.3 对于同步方法块,锁是Synchonized括号里配置的对象

public class SynchronizedDemo {

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo=new SynchronizedDemo();
        
        //锁是Synchonized括号里配置的对象
        synchronized (synchronizedDemo){

        }
        
    }
    
}

2.synchronized的实现原理

在如下的例子中,使用了同步块和同步方法,通过使用javap工具查看生成的class文件信息来分析synchronized关键字的实现细节

public class Synchronized {

	public static void main(String[] args){
		// 对Synchronized Class对象进行加锁
		synchronized (Synchronized.class){
				
		}
        // 静态同步方法,对Synchronized Class对象进行加锁
        m();
     }
     
    public static synchronized void m(){
   
   }
}

在Synchronized.class同级目录执行javap–v Synchronized.class,部分相关输出如下所示:

public static void main(java.lang.String[]);
    // 方法修饰符,表示:public staticflags: ACC_PUBLIC, ACC_STATIC
    Code:
        stack=2, locals=1, args_size=1
        0: ldc #1  // class com/murdock/books/multithread/book/Synchronized
        2: dup
        3: monitorenter  // monitorenter:监视器进入,获取锁
        4: monitorexit  // monitorexit:监视器退出,释放锁
        5: invokestatic  #16 // Method m:()V
        8: return
    public static synchronized void m();
     // 方法修饰符,表示: public static synchronized
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
          Code:
               stack=0, locals=0, args_size=0
               0: return

由上面的信息可知:

  • 同步块的实现原理:同步块的实现使用了monitorenter和monitorexit指令,monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。
  • 同步方法的实现原理:同步方法依靠方法修饰符上的ACC_SYNCHRONIZED来完成的
  • 无论采用哪种方式,其本质是对一个对象的监视器(monitor)进行获取,而这个获取过程是排他的,也就是同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。

任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用
时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法,而没有获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED状态。

图4-2描述了对象、对象的监视器、同步队列和执行线程之间的关系。
在这里插入图片描述

从图4-2中可以看到,任意线程对Object(Object由synchronized保护)的访问,首先要获得Object的监视器。如果获取失败,线程进入同步队列,线程状态变为BLOCKED。

当获得了锁的线程释放了锁,则该释放操作唤醒阻塞在同步队列中的线程,使其重新尝试对监视器的获取。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
synchronized关键字是Java中用于实现线程同步的关键字。它可以应用于方法或代码块,确保在同一时间只有一个线程能够访问被synchronized修饰的代码块或方法。 实现原理主要包括以下几个方面: 1. 监视器锁(Monitor Lock):每个Java对象都有一个监视器锁,可以抽象地理解为对象内部的一种标记。当一个线程访问synchronized代码块或方法时,它会尝试获取对象的监视器锁,如果获取成功,则进入临界区执行代码;如果获取失败,则线程进入阻塞状态,直到获得锁为止。 2. 内存屏障(Memory Barrier):synchronized关键字不仅保证了互斥性(即同一时间只有一个线程能够执行synchronized代码块或方法),还保证了可见性和有序性。在释放锁之前,会将对共享变量的修改刷新到主内存中;在获取锁之前,会从主内存中重新读取共享变量的值,确保每个线程看到的共享变量值一致。 3. 重入性(Reentrancy):synchronized关键字是可重入的,即同一个线程可以多次获取同一个对象的监视器锁而不会发生死锁。每次获取锁时,锁的计数器会递增,释放锁时计数器递减,只有当计数器为0时才真正释放锁。 4. 互斥性(Mutual Exclusion):synchronized关键字保证了临界区的互斥性,同一时间只有一个线程能够执行被synchronized修饰的代码块或方法。其他线程需要等待当前占用锁的线程释放锁后才能继续执行。 需要注意的是,synchronized关键字只能用于同一个进程或线程内部的同步,不能用于不同进程或线程之间的通信和同步。在Java 5及之后,还引入了更灵活的Lock和Condition接口来替代synchronized关键字,提供了更多高级的线程同步操作和更细粒度的控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Turbos01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值