synchronized是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。本文给大家介绍java中的用法。

一、为什么要使用synchronized

在并发编程中存在线程安全问题,主要原因有:

1.存在共享数据

2.多线程共同操作共享数据。

关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性),即可以代替volatile。

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性

二、synchronized的用法

synchronized可以修饰静态方法、成员函数,同时还可以直接定义代码块,但是归根结底它上锁的资源只有两类:一个是对象,一个是

  1. 修饰普通方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁
  2. 修饰静态方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁
  3. 修饰方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

三、实现原理

我们先通过反编译下面的代码来看看Synchronized是如何实现对代码块进行同步的:

 package com.paddx.test.concurrent;public class SynchronizedDemo {public void method() {synchronized (this) {System.out.println("Method 1 start");}}}

反编译结果:

关于这两条指令的作用,我们直接参考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的所有权。

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

我们再来看一下同步方法的反编译结果:

源代码:

1 package com.paddx.test.concurrent;
2
3 public class SynchronizedMethod {
4     public synchronized void method() {
5         System.out.println("Hello World!");
6     }
7 }

反编译结果:

从反编译的结果来看,方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。

四、总结

Synchronized是Java并发编程中最常用的用于保证线程安全的方式,其使用相对也比较简单。但是如果能够深入了解其原理,对监视器锁等底层知识有所了解,一方面可以帮助我们正确的使用Synchronized关键字,另一方面也能够帮助我们更好的理解并发编程机制,有助我们在不同的情况下选择更优的并发策略来完成任务。

Java并发篇_synchronized相关推荐

  1. 我的2017年文章汇总——Java并发篇

    近期准备把过去一年写的文章按照分类重新整理推送一遍,包括:"分布式"."机器学习"."深度学习"."NLP"." ...

  2. Java并发篇_乐观锁与悲观锁

    乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展. 一.引入概念 1.悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次 ...

  3. Java并发篇_volatile

    volatile是Java提供的一种轻量级的同步机制.Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为 ...

  4. Java并发篇_Java内存模型

    在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题.那么它们产生的原因和在Java中解决的办法又是什么呢? 一.内存模型的相关概念 ​ 计算机在执行程序时,每条指令都是在CP ...

  5. Java并发篇_线程详解

    线程(thread) 是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 ...

  6. Java并发篇_进程线程

    一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存在,它必须是进程的一部分.一个进程一直运行,直到所有的非守护线程都结束运行后才能结束. 多线程能满足程序员编写高效率的程序 ...

  7. JAVA并发篇_公平锁与非公平锁

    简单的来说,如果一个线程组里,能保证每个线程都能拿到锁,那么这个锁就是公平锁.相反,如果保证不了每个线程都能拿到锁,也就是存在有线程饿死,那么这个锁就是非公平锁. 一.引入概念 1.公平锁: 多个线程 ...

  8. java并发编程入门_探讨一下!Java并发编程基础篇一

    Java并发编程想必大家都不陌生,它是实现高并发/高流量的基础,今天我们就来一起学习这方面的内容. 什么是线程?什么是进程?他们之间有什么联系? 简单来说,进程就是程序的一次执行过程,它是系统进行资源 ...

  9. Java并发编程|第二篇:线程生命周期

    文章目录 系列文章 1.线程的状态 2.线程生命周期 3.状态测试代码 4.线程终止 4.1 线程执行完成 4.2 interrupt 5.线程复位 5.1interrupted 5.2抛出异常 6. ...

最新文章

  1. SQLStoredProc调用数据库存储过程
  2. [MATLAB学习笔记] global声明全部变量
  3. 比亚迪汉鸿蒙系统测评_比亚迪汉性能强悍,麋鹿测试成绩超80km/h
  4. Vuex 源码还有一些缺陷?
  5. FxCAD 实验三 实现对象的【属性】事件
  6. mysql 5.6 5.7不兼容_同一条sql在mysql5.6和5.7版本遇到的问题。
  7. html资源文件放在哪里,09 Spring Boot开发web项目之静态资源放哪里?
  8. window ftp open命令打不开_Centos7上搭建ftp
  9. android 样式预处理,基于Android平台的字符识别预处理算法设计与实现
  10. 电信版本-中兴B860AV1.1-T-S905M-B NAND闪存 线刷救砖固件
  11. 企业微信的一周小结是怎么统计的?
  12. python转html_Python 将文本转换成html的简单示例
  13. 【学习笔记】山东大学生物信息学-08 编程基础与网页制作
  14. 双系统装完只能u盘启动_怎样用u盘安装双系统呢?
  15. 360安全卫士极速版修改浏览器主页
  16. iOS Xcode:No account for team 5P2U9V6DNN.
  17. 常用电子元器件及应用
  18. dcm格式的文件里有什么,哪些对于深度学习模型训练有用
  19. 判断键盘输入的数是几位数且是否是回文数
  20. 部分喷墨机初始化方法打印机清零

热门文章

  1. apache禁止多目录运行php文件下载,Nginx Apache下如何禁止指定目录运行PHP脚本
  2. 设置 Visual Studio 文件版权信息 - C语言零基础入门教程
  3. Python set集合 - Python零基础入门教程
  4. react之虚拟DOM的两种创建方式
  5. BugkuCTF-Crypto题简单加密
  6. c语言程序设计安徽区笔试部分,2021年安徽省二级C语言程序设计笔试样题-20210419093521.doc-原创力文档...
  7. java推送Comet_使用Comet4j实现消息推送
  8. redhat9安装mysql_redhat 9.0 安装mysql
  9. php数据回显是什么意思,jquery回显是什么意思
  10. java创建型_Java创建型模式