前面说过,Java对象都有与之关联的一个内部锁和监视器
内部锁是一种排它锁,能够保障原子性、可见性、有序性
从Java语言层面上说,内部锁使用synchronized关键字实现
synchronized可以修饰方法,静态方法和实例方法都可以,也可以修饰一段代码({} 包裹)
synchronized修饰的方法被叫做同步方法
  • 修饰的静态方法叫做同步静态方法
  • 修饰的实例方法叫做同步实例方法
  • synchronized修饰的代码块(或者一整个方法)就是曾经说过的临界区
synchronized关键字同步机制的使用,需要借助于锁对象
synchronized关键字修饰静态方法,锁对象隐含的是该类的class实例对象;修饰的实例方法隐含的是该对象本身(this)
对于同步代码段,则需要显式的指定锁对象

示例

注意:
对于锁对象,应该声明为final的
因为如果一旦锁对象发生了变化,那么很可能使用的将不是同一个锁对象,也就失去了同步的意义了,更甚一步,通常声明为private final
如上代码示例,借助于synchronized关键字,就可以实现原子性、可见性、有序性,所以对于该临界区内的代码,必然不会出现线程安全问题
但是这是一种排他锁,也就是对临界区的处理串行化,所以势必影响性能

锁泄漏

对于synchronized来说,这是一种内部锁,对于锁的申请和释放,都是借助于底层实现的,换句话说你只需要使用synchronized关键字即可
底层JVM会帮助我们实现锁的获取与锁的释放,即使出现问题,也会释放锁,所以synchronized的内部锁不存在锁泄露问题
对于锁泄漏,有时候可能是同一个线程持续操作,由于锁的可重入性,所以并不会发现问题,但是对于高并发,这就很可能爆发出来问题了

调度

Java虚拟机会给每个内部锁分配一个入口集 Entry Set,用于记录等待获得内部锁的线程
多个线程竞争时,只会有一个线程获得锁,其他线程获取失败,会进入BLOCKED等待状态,位于入口集的等待区中
锁释放后,会随机的唤醒一个线程,Java虚拟机内部对于内部锁是非公平的,也仅仅支持非公平调度,唤醒的线程可能会跟其他的线程竞争,所以他并不一定可以竞选成功,可能会被再次置入等待状态
这个过程跟前面介绍的监视器的过程是一样的

锁对象的确认

前面提到
synchronized修饰的同步实例方法,锁对象为当前对象本身this;静态方法锁对象为该类型对应的xxx.class对象实例;
这都是隐式的,如何确认?其实很简单
可以定义另外的方法显式的声明锁对象为该对象this或者xxx.class对象实例,对其中一个线程进行sleep,观察显式方法对锁的获取情况,就可以佐证这一结论。
如果是不同的锁的话,将不会收到任何影响,如果是同一个锁就需要进行等待。

同步继承性

synchronized关键字修饰的方法可以进行同步,对于同步方法的继承性是什么样子的?
比如父类中
public synchronized void service();
子类中
@override
public void service();
对于子类中的方法调用,并不会具有同步的特性,所以,一个方法是否具有同步的特性,在于这个方法本身是否有synchronized修饰

同步代码块

synchronized即可以修饰方法,也可以修饰代码块
为什么还要用同步代码块?直接加到方法上多省事儿?
synchronized同步保障了原子性、可见性、有序性,这个内部锁机制是排他的,换言之,相当于部分串行
串行自然可以解决多线程安全问题,如果整个项目全部都是synchronized的方法,那么肯定不会有线程安全问题,但是为什么不这么做?还不是因为性能问题,多核CPU放在那里,难道就只是摆设嘛
既然是相当于串行,很显然,串行化的代码越多,那么效率必然将会越低,所以希望减少非必要的串行化,留给多核机器以及编译器CPU更多的优化空间
所以同步代码块顺势而出
同步代码块保障了更少的“串行化”代码,那么一个方法中,同步代码块之外的代码是如何进行的?是异步的!
进入同步代码块之前会多线程并发,但是一旦执行到同步代码块,将会串行

小结

对于synchronized关键字,从应用层面上来说是非常简单的,就只有代码中的三种样式,但是底层的原理是很复杂的,涉及到JMM以及原子性、可见性、有序性的概念
所以想要学习synchronized,务必要理解这些概念
对于多线程编程来说,synchronized更大程度上来说,更相当于是一个语法糖,底层的机制全部被封装了,如果理解了底层的概念,语法糖的东西,就没什么理解难度
原子性、可见性、有序性是问题根源,JMM是问题解决方案,编译器、JVM底层负责实现,synchronized只是一个关键字而已,但是synchronized却是完全代表了底层的一切
为什么说synchronized关键字修饰的方法(代码段)是线程安全的?那是因为底层的原子性、可见性、有序性的保障。
Java中任何一个对象都有与之关联的内部锁和监视器,所以任何的一个对象都可以用来作为锁对象
所以,借助于synchronized关键字和锁对象,进行合理的安排,你一定可以编写出来正确的并发程序(自身的安排组织不当怪不得synchronized)

synchronized关键字简介 多线程中篇(十一)的更多相关文章

  1. Java内存模型JMM 高并发原子性可见性有序性简介 多线程中篇(十)

    JVM运行时内存结构回顾 在JVM相关的介绍中,有说到JAVA运行时的内存结构,简单回顾下 整体结构如下图所示,大致分为五大块 而对于方法区中的数据,是属于所有线程共享的数据结构 而对于虚拟机栈中数据 ...

  2. Java多线程概念简介 多线程中篇(一)

    Java的线程与操作系统的线程   在线程的相关介绍中,有讲到“线程的实现”分为三种:内核支持,用户级以及两者混合.(这只是一种简要的分类) Java线程在JDK1.2之前,是用户线程实现的 而在JD ...

  3. JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

    JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...

  4. 用代码说话:synchronized关键字和多线程访问同步方法的7种情况

    synchronized关键字在多线程并发编程中一直是元老级角色的存在,是学习并发编程中必须面对的坎,也是走向Java高级开发的必经之路. 一.synchronized性质 synchronized是 ...

  5. Synchronized关键字与多线程

    在java中,每一个对象有且仅有一个同步锁.这也意味着,同步锁是依赖于对象而存在.当我们调用某对象的synchronized方法时,就获取了该对象的同步锁.例如,synchronized(obj)就获 ...

  6. Java 多线程 —— synchronized关键字

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  7. 2.3多线程(java学习笔记)synchronized关键字

    一.为什么要用synchronized关键字 首先多线程中多个线程运行面临共享数据同步的问题. 多线程正常使用共享数据时需要经过以下步骤: 1.线程A从共享数据区中复制出数据副本,然后处理. 2.线程 ...

  8. java中synchronized关键字基础-1

    1.synchronized关键字简介 synchronized是java中的一个关键字,在中文中为同步,也被称之为'同步锁',以此来达到多线程并发访问时候的并发安全问题,可以用来修饰代码块.非静态方 ...

  9. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

随机推荐

  1. Python《学习手册:第二章-习题》

    什么是Python解释器? Python解释器是运行Python程序的程序. 什么是源代码? 源代码是为程序所写的语句:它包括文本文件(通常以.py为文件名结尾)的文件. 什么是字节码? 字节码是Py ...

  2. JAVAEE——Mybatis第一天:入门、jdbc存在的问题、架构介绍、入门程序、Dao的开发方法、接口的动态代理方式、SqlMapConfig.xml文件说明

    1. 学习计划 第一天: 1.Mybatis的介绍 2.Mybatis的入门 a) 使用jdbc操作数据库存在的问题 b) Mybatis的架构 c) Mybatis的入门程序 3.Dao的开发方法 ...

  3. HTTP相关:TCP/IP、DNS

    最近在看HTTP的书,看得有点慢,而且断断续续的,很多东西看完就忘了.知识点多且零散,感觉要多看几遍才能消化. TCP/IP协议族按层次分为4层: 应用层: 应用层决定了向用户提供应用服务时通信的活动 ...

  4. 几张图帮你理解 docker 基本原理及快速入门

    写的非常好的一篇文章,不知道为什么被删除了.  利用Google快照,做个存档. 快照地址:地址 作者地址:青牛 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 do ...

  5. select case when与IF的用法

    case when概述 sql语句中的case语句与高级语言中的switch语句,是标准sql的语法,适用于一个条件判断有多种值的情况下分别执行不同的操作. case when示例 有一张表,里面有3 ...

  6. 使用SimHash进行海量文本去重[转载]

    阅读目录 1. SimHash与传统hash函数的区别 2. SimHash算法思想 3. SimHash流程实现 4. SimHash签名距离计算 5. SimHash存储和索引 6. SimHas ...

  7. Cookie防篡改机制

    一.为什么Cookie需要防篡改 为什么要做Cookie防篡改,一个重要原因是 Cookie中存储有判断当前登陆用户会话信息(Session)的会话票据-SessionID和一些用户信息. 当发起一个 ...

  8. java编程思想-第五章-某些练习题

    参考https://blog.csdn.net/caroline_wendy/article/details/46844651 10&11 finalize()被调用的条件 Java1.6以下 ...

  9. golang使用Nsq

    为什么要使用Nsq 最近一直在寻找一个高性能,高可用的消息队列做内部服务之间的通讯.一开始想到用zeromq,但在查找资料的过程中,意外的发现了Nsq这个由golang开发的消息队列,毕竟是golan ...

  10. [Poi2014]FarmCraft 树状dp

    对于每个点,处理出走完其子树所需要的时间和其子树完全下载完软件的时间 易证,对于每个点的所有子节点,一定优先选择差值大的来给后面的时间 树规+贪心. #include<cstdio> #i ...