并发编程中用到最多的关键字就是synchronized。下面来探究一下synchronized:

  • synchronized如何使用?
  • synchronized是如何实现同步加锁的,原理是什么?
  • synchronized解决了并发编程的哪些问题?

1 synchronized使用

1.1 线程安全问题

并发编程中,当多个线程同时访问同一个资源的时候,就会引发线程安全问题。

由于每个线程执行的过程是不可控的,所以很有可能导致最终的结果和实际期望的结果违背或者直接导致程序出错。

例子

public class VolatileTest{    public int inc = 0;    public void increase(){        inc++;    }    public static void main(String[] args){        final VolatileTest test = new VolatileTest();        for(int i = 0; i < 10; i++){            new Thread(){                public void run(){                    for(int j = 0; j < 1000 ; j++){                        test.increase();                    }                }            }.start();        }        while(Thread.activeCount()>1){            Thread.yield();            System.out.println(test.inc);        }    }}

目的:test.inc = 10000;

结果: 多次执行得到的结果都小于10000;

分析: 多个线程同时读到inc的值,并对其进行加1的操作, 导致多次操作只对inc的值只增加了1。

基本上所有的并发模式在解决线程安全问题的时候,都会采用对临界资源进行序列化访问的方式,简单来说就是,在同一时刻,只能有一个线程访问该临界资源,实现同步互斥访问。通常来说,就是在临界资源代码前进行加锁的操作,必须先获得锁,才能访问,访问完毕后释放锁,其他线程可以访问。在java中,提供了两种方式来实现同步互斥访问:synchronized和lock复制代码

1.2 synchronized用法

  • 普通同步方法,锁是当前实例对象
  • 静态同步方法,锁是当前类的class对象
  • 同步方法块,锁是括号里面的对象

例子

public class MyClass{    int count;       // 1.实例方法    public synchronized void add(int value){        count += value;    }       // 2.实例方法中的同步块 (等价于1)    public void add(int value){        synchronized(this){            count += value;        }    }       // 3.静态方法    public static synchronized void add(intvalue){         count += value;    }       // 4.静态方法中的同步块 (等价于3)    public static void add(int value){        synchronized(MyClass.class){            count += value;        }    }}

2. 原理探究

如下代码,利用javap工具查看生成的class文件信息来分析Synchronized的实现。 代码:

public class synchronized Test {    // 同步代码块    public void doSth1(){       synchronized (synchronizedTest.class){           System.out.println("HelloWorld");       }    }    // 同步方法    public synchronized void doSth2(){        System.out.println("HelloWorld");    }}

使用javap对class文件进行反编译后结果:

javap命令:

D:installjavajdk8binjavap.exe -v .synchronizedTest.class

从反编译后的结果中可以看到:对于同步方法,JVM采用ACC_synchronized标记符来实现同步。对于同步代码块。JVM采用monitorenter、monitorexit两个指令来实现同步。

同步代码块

JVM采用monitorenter、monitorexit两个指令来实现同步。 查询JVM规范The Java® Virtual Machine Specification[1]中关于monitorenter和monitorexit的介绍:

大致内容如下:

  • 可以把执行monitorenter指令理解为加锁,执行monitorexit理解为释放锁。
  • 每个对象维护着一个记录着被锁次数的计数器。
  • 未被锁定的对象的该计数器为0,当一个线程获得锁(执行monitorenter)后,该计数器自增变为1,当同一个线程再次获得该对象的锁的时候,计数器再次自增。当同一个线程释放锁(执行monitorexit指令)的时候,计数器再自减。
  • 当计数器为0的时候。锁将被释放,其他线程便可以获得锁。

同步方法

JVM采用ACC_synchronized标记符来实现同步。 查询JVM规范The Java® Virtual Machine Specification[2]中关于方法级同步的介绍:

大致内容如下

  • 方法级的同步是隐式的。同步方法的常量池中会有一个ACC_synchronized标志。
  • 当某个线程要访问某个方法的时候,会检查是否有ACC_synchronized,如果有设置,则需要先获得监视器锁(monitor),然后开始执行方法,方法执行之后再释放监视器锁。这时如果其他线程来请求执行方法,会因为无法获得监视器锁而被阻断住。
  • 值得注意的是,如果在方法执行过程中,发生了异常,并且方法内部并没有处理该异常,那么在异常被抛到方法外面之前监视器锁会被自动释放。

3 Monitor

无论是同步方法还是同步代码块都是基于监视器Monitor实现的

Monitor是什么

所有的java对象是天生的Monitor,每一个Java对象都有称为Monitor的潜质,因为在Java的设计中,每一个对象天生就带了一把看不见的锁,它叫做内部锁或者Monitor锁。

每个对象都存在着一个Monitor与之关联,对象与其Monitor之间的关系有存在多种实现方式,如Monitor可以与对象一起创建销毁。

Moniter如何实现线程的同步?

在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的(位于HotSpot虚拟机源码ObjectMonitor.hpp文件,C++实现的)。

ObjectMonitor中有几个关键属性:

_owner:指向持有ObjectMonitor对象的线程

_WaitSet:存放处于wait状态的线程队列

_EntryList:存放处于等待锁block状态的线程队列

_recursions:锁的重入次数

_count:用来记录该线程获取锁的次数

  • 线程T等待对象锁:_EntryList中加入T。
  • 线程T获取对象锁:_EntryList移除T,_owner置为T,计数器_count加1。
  • 线程T中锁对象调用wait():_owner置为null,计数器_count减1,_WaitSet中加入T等待被唤醒。
  • 持有对象锁的线程T执行完毕:复位变量的值,以便其他线程进入获取monitor

5 总结

多并发编程中通过同步互斥访问临界资源来解决线程安全问题,Java中常用synchronized标记同步块达到加锁的目的。

synchronized用法有两种,修饰方法和修饰同步代码块。

synchronized的实现原理:每一个Java对象都会关联一个Monitor,通过Monitor对线程的操作实现synchronized对象锁。

并发编程中synchronized可以保证原子性、可见性、有序性。

synchronized()_深入理解synchronized相关推荐

  1. java synchronized 参数_个人对synchronized锁的参数理解,如果有误望指出

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 synchronized有几种用法 给方法加锁也就是在声明方法时加上synchronized关键字,这样同时就只能有一个线程访问该方法 其次就是代码块,s ...

  2. synchronized()_这篇文章带你彻底理解synchronized关键字

    Synchronized关键字一直是工作和面试中的重点.这篇文章准备彻彻底底的从基础使用到原理缺陷等各个方面来一个分析,这篇文章由于篇幅比较长,但是如果你有时间和耐心,相信会有一个比较大的收获,所以, ...

  3. 存储过程没有执行完后没有释放锁_【大厂面试07期】说一说你对synchronized锁的理解?...

    PS:本文已收录到1.3 K+ Star 数的开源项目-<大厂面试指北>,如果想要了解更多,可以看一看,项目地址如下: https://github.com/NotFound9/inter ...

  4. Java中 synchronized 关键字的理解

    synchronized 关键字的理解 在Java中,synchronized 是一个重量级的控制并发的关键字. 这个关键字可以保证并发过程所必须的"原子性","可见性& ...

  5. synchronized原理_浅谈synchronized的实现原理

    Synchronized是Java中的重量级锁,在我刚学Java多线程编程时,我只知道它的实现和monitor有关,但是synchronized和monitor的关系,以及monitor的本质究竟是什 ...

  6. 深入理解synchronized

    深入理解synchronized 线程安全问题 临界区( Critical Section) 竞态条件( Race Condition ) synchronized 的使用 加锁方式 synchron ...

  7. 理解synchronized的含义

    理解synchronized的含义 1.synchronized就是给当前的NumOps类型的对象添加了一个互斥锁机制:锁只能有一个 2.当有一个线程正在某个同步方法中执行,则其它线程不能进入该对象的 ...

  8. 并发编程之深入理解synchronized

    并发编程之深入理解synchronized 一.java共享内存带来的线程安全问题 1.1 问题分析 1.2 临界区 1.3 竞态条件 二.synchronized使用 2.1 解决之前的共享问题 三 ...

  9. 深入理解Synchronized(一)

    一.简介 JMM(Java Memory Model,Java内存模型)规范定义Java的共享内存模型,但共享内存模型随之带来的就是共享变量的线程安全问题,对JMM的理解可以参看<Java 内存 ...

最新文章

  1. 如何加入家庭组计算机打印机,如何使用利用win7家庭组打印机
  2. 最值得阅读学习的 10 个 C 语言开源项目代码
  3. python算法与数据结构-单链表
  4. 列举python的5个数据类型_python公开课|新公布的5个python核心数据类型,这些细节你难道还不不知道吗...
  5. TextView实现自动滚动滚动.
  6. 该文件没有与之关联的程序来执行该操作_Liunx tty子系统分析之三 tty字符设备文件操作接口说明...
  7. 一加到1亿。C语言_可能是今年最难选的2部手机:小米10详细对比一加8T
  8. Vert.x 之 HelloWorld
  9. 计算机应用基础实例,计算机应用基础案例教程(Windows 7+Office 2010)
  10. java项目中使用kettle的JNDI连接配置
  11. sharepoint安装心得-.net与sharepoint安装 sharepoint安装心得_过程(一)
  12. 联想式查单词-YourDict
  13. 微信小程序下拉刷新真机没效果_微信小程序下拉刷新上拉加载的两种实现方法...
  14. python抓取电影海王影评词云生成
  15. 金融危机对中国IT产业四大深层影响
  16. 技术分享杂七杂八技术
  17. hp-unix操作系统root账号被锁定的两种解决方法:
  18. 详细分析推荐系统和搜索引擎的差异陈运文
  19. 通过Java访问数据库---JDBC
  20. 1.初接触思科模拟器

热门文章

  1. 学习Node.js并开始在浏览器之外执行JavaScript
  2. 如何使用消息队列,Spring Boot和Kubernetes扩展微服务
  3. c# url编码 字母编码_我如何通过每天30分钟编码来完成#100DaysOfCode挑战
  4. c语言二分法_14个经典C语言算法你就不看一眼?(附详细代码)
  5. ping32终端安全管理系统_文档安全之Ping32文档外发管控使用详解
  6. 缺少Python27_d.lib的解决方法
  7. Python初学者的自我修养,找到自己的方向
  8. Python下载网络图片方法汇总与实现
  9. 利用 Python 写一个颜值测试小工具
  10. C# LINQ to XML