博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Synchronized关键字
阅读量:7112 次
发布时间:2019-06-28

本文共 3606 字,大约阅读时间需要 12 分钟。

Java中的每一个对象都可以作为锁,具体表现为以下3种形式:

- 对于普通同步方法,锁是当前实例对象
- 对于静态同步方法,锁是当前类的Class对象
- 对于同步代码块,锁是Synchronized括号里配置的对象

synchronized作用于四种类型:

1. 实例方法
2. 静态方法
3. 实例方法中的同步块
4. 静态方法中的同步块

同步方法

实例同步方法

public synchronized void add(int value){    this.count += value;}

Java实例方法同步是同步在拥有该方法的对象上。这样,每个实例其方法同步都同步在不同的对象上,即该方法所属的实例。只有一个线程能够在实例方法同步块中运行。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行操作。一个实例一个线程。

静态同步方法

public static synchronized void add(int value){    count += value;}

静态方法的同步是指同步在该方法所在的类对象上。因为在Java虚拟机中一个类只能对应一个类对象,所以同时只允许一个线程执行同一个类中的静态同步方法。

同步代码块

synchronized(object){}

实例方法中的同步代码块

public void add(int value){    synchronized(this){       this.count += value;    }}

在上例中,使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。上述代码使用监视器对象同步,同步实例方法使用调用方法本身的实例作为监视器对象。

在Spring的AbstractApplicationContext中:

/** Synchronization monitor for the "refresh" and "destroy" */private final Object startupShutdownMonitor = new Object();@Overridepublic void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {        // Prepare this context for refreshing.        prepareRefresh();        // Tell the subclass to refresh the internal bean factory.        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();        // Prepare the bean factory for use in this context.        prepareBeanFactory(beanFactory);        //......    }}@Overridepublic void registerShutdownHook() {    if (this.shutdownHook == null) {        // No shutdown hook registered yet.        this.shutdownHook = new Thread() {            @Override            public void run() {                synchronized (startupShutdownMonitor) {                    doClose();                }            }        };        Runtime.getRuntime().addShutdownHook(this.shutdownHook);    }}@Overridepublic void destroy() {    close();}@Overridepublic void close() {    synchronized (this.startupShutdownMonitor) {        doClose();        // If we registered a JVM shutdown hook, we don't need it anymore now:        // We've already explicitly closed the context.        if (this.shutdownHook != null) {            try {                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);            }            catch (IllegalStateException ex) {                // ignore - VM is already shutting down            }        }    }}

静态方法中的同步代码块

public class MyClass {
public static synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } }}

这两个方法不允许同时被线程访问。

如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。

关于synchronized(this)

synchronized(this){}

对于synchronized(this)有如下理解:

1、当两个并发线程访问同一个对象object中synchronized(this)代码块时,只能有一个线程得到执行。
2、当一个线程访问此同步代码块,另一个线程仍然可以访问非同步代码块。
3、当一个线程访问某个同步代码块时,其他线程对object中其他同步代码块的访问也将被阻塞。

实现原理

从JVM规范中可以看到Synchroinzed在JVM里的实现原理,JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者实现细节不一样。代码块的同步是使用monitorenter和monitorexit指令实现的。

monitorenter指令时在编译后插入到同步代码块的开始位置,monitorexit则是插入到方法结束处和异常处。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获取对象的锁。

Java对象头

synchronized用的锁是存在Java对象头里的。对象头中的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。

Java的线程时映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,因此状态转换需要耗费很多的处理器时间。所以synchronized是Java语言中一个重量级的操作,有经验的程序员都会在确实有必要的情况下才使用这种操作。而虚拟机本身也会进行一些优化。

锁的升级与对比

Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,1.6中锁一共四种状态,级别由低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级,但不能降级。

 

转载于:https://www.cnblogs.com/lucare/p/8679142.html

你可能感兴趣的文章
Ajax-ajax实例1-动态加载的 FAQ
查看>>
破解电信光猫华为HG8120C关闭路由功能方法
查看>>
分布式系统事务一致性解决方案大对比
查看>>
Java中ArrayList的初始容量和容量分配
查看>>
Spring-WebSocket 教程
查看>>
hexo 博客支持PWA和压缩博文
查看>>
C#快速剔除字符串中不合法的文件名或者文件路径字符
查看>>
用spring boot 2从零开始创建区块链
查看>>
Android中渐变图片失真的解决方案
查看>>
Java基础-SSM之mybatis的统计函数和分页查询
查看>>
cpu压力测试
查看>>
Linux共享库 zlog日志
查看>>
一个有趣的python排序模块:bisect
查看>>
IOS Tutorial -- 1) Objective-C Basics
查看>>
理解.NET程序集的执行过程
查看>>
工作经验总结
查看>>
Oracle 触发器 插入,更新,删除,数据同步,两表同步
查看>>
学习从模仿开始 —— 模仿UI 导航帖
查看>>
C#接口-接口作为参数
查看>>
MBR
查看>>