博客
关于我
多线程系列--synchronized
阅读量:514 次
发布时间:2019-03-07

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

其他网址

参考网址:

简介

作用

        保证原子性、可见性。

        只要保证多个线程使用同一个“对象监视锁”,就能保证同步。

用法

用法

对象监视器

示例

修饰普通方法

当前实例对象

public synchronized void increase() {

    i++;

}

修饰静态方法

当前类的class对象

public static synchronized void increase() {

    i++;

}

修饰代码块

括号里边的对象。

这个对象可以是实例对象(例如this),也可以是class对象(例如:XXX.class或者this.getClass())。

public Object synMethod(Object a1) {

    synchronized(a1) {

        // 操作

    }

}

原理

源码探寻

Test.java

public class Test {    private static Object LOCK = new Object();    public static int main(String[] args) {        synchronized (LOCK){            System.out.println("Hello World");        }        return 1;    }}

先用javac Test.class 编译出class文件

再用javap –c Test.class查看字节码文件

字节码文件:

也就是说,锁是通过monitorenter和monitorexit来实现的。

进入监视器

JVM规范中描述:

    monitorenter:` Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows: • If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor. • If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count. • If another thread already owns the monitor associated with objectref, the thread blocks until the monitor’s entry count is zero, then tries again to gain ownership. `

翻译:

        每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

  1. 如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
  2. 如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
  3. 如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

退出监视器

JVM规范中描述:

monitorexit:  ` The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref. The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.`       

翻译:

        执行monitorexit的线程必须是objectref所对应的monitor的所有者。
        指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。

        Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

synchronized与volatile比较

比较方面

synchronized

volatile

作用

锁定当前对象,只有当前线程可以访问该对象,其他线程被阻塞。

本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;

使用范围

变量、方法、和类

变量

线程安全

可以保证变量的可见性和原子性

仅能实现变量的可见性,不能保证原子性

阻塞

可能会造成线程的阻塞

不会造成线程的阻塞

优化

标记的变量可以被编译器优化

标记的变量不会被编译器优化

synchronized与Lock比较

参考网址:

synchronized

Lock

存在层面

java 内置关键字,在 jvm 层面

java 类(实际是一个接口),在API层面

锁的释放

会自动释放锁:

线程执行完同步代码会释放锁 ;

线程执行中发生异常会释放锁

需在 finally 中手工释放锁(unlock()方法释放锁)

锁的获取

若线程 1 获得锁,线程 2 等待;

若线程 1 阻塞,线程 2 会一直等待

分情况而定,Lock有多个获得锁的方式。

可尝试获得锁,线程可以不用一直等待

锁状态

无法判断是否已经获取锁

可判断是否已经获取到锁

锁类型

可重入、不可中断、非公平

(只能等待锁释放,不能响应中断)

可重入、可中断、可公平(两者皆可)

(等待锁时可用interrupt来中断等待)

适用场景

大量同步的代码

少量代码的同步

性能

jdk1.6以前:重量级锁(无法取得锁即挂起)

jdk1.6之后:优化了性能:给它的锁加入了四种状态,无锁状态 -> 偏向锁 -> 轻量级锁 -> 重量级锁,自动进行锁的升级。

jdk1.6以后:

竞争资源不激烈时:两者性能差不多

竞争资源激烈时:Lock性能远远好于synchronized

synchronized与ReentrantLock比较

参考网址:

相同点

1. 它们都是加锁方式同步;

2. 都是可重入锁;
3. 阻塞式的同步;

不同点

因为ReentrantLock实现了Lock,所以拥有synchronized与Lock的所有不同点,其他不同点如下:

1. 多个线程在等待的时候,可以提供公平的锁;默认的是非公平锁,性能会比公平锁好一些;
2. ReenTrantLock 可以绑定多个锁条件

转载地址:http://dhvjz.baihongyu.com/

你可能感兴趣的文章
NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
查看>>
NIFI从Oracle11G同步数据到Mysql_亲测可用_解决数据重复_数据跟源表不一致的问题---大数据之Nifi工作笔记0065
查看>>
NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
查看>>
nifi使用过程-常见问题-以及入门总结---大数据之Nifi工作笔记0012
查看>>
NIFI分页获取Mysql数据_导入到Hbase中_并可通过phoenix客户端查询_含金量很高的一篇_搞了好久_实际操作05---大数据之Nifi工作笔记0045
查看>>
NIFI分页获取Postgresql数据到Hbase中_实际操作---大数据之Nifi工作笔记0049
查看>>
NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
查看>>
NIFI同步MySql数据源数据_到原始库hbase_同时对数据进行实时分析处理_同步到清洗库_实际操作06---大数据之Nifi工作笔记0046
查看>>
Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
查看>>
【Flink】Flink 1.9 版本 web UI 突然没有日志
查看>>
NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_处理器介绍_处理过程说明---大数据之Nifi工作笔记0019
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_实际操作---大数据之Nifi工作笔记0020
查看>>