什么是synchronized

synchronized可以保证某个代码块或者方法被一个线程占有,保证了一个线程的可先性。java 1.6之前是重量级锁,在1.6进行了各种优化,就不那么重了,并引入了偏向锁和轻量级锁,以及锁的存储结构和升级过程。

synchronized实现方式

Java中每个对象都可以作为锁:

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

synchronized实现原理

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

JVM基于进入和退出Monitor对象来实现方法同步和代码块同步。通过monitorenter和monitorexit指令实现。前者是编译后插入到同步代码块开始的位置,后者是插入到方法结束和异常处。JVM保证每个monitorenter和monitorexit指令是配对的,任何对象都会有一个monitor与之关联,当对对象的monitor被持有后,它就是处于锁定状态。线程执行到monitorenter时,就会尝试获取对象monitor的所有权,就是获取对象锁。

sychronized 特点

  1. 不能被继承,但是可以调用父类的同步方法达到同步的目的。
  2. 一个线程访问一个对象的synchronized方法或者代码块的时候,其他线程访问该对象的synchronized方法或者代码块将被阻塞,但是非synchronized方法或者代码块还是可以访问 的。
  3. 不论sychronized 放在对象还是方法上,如果它作用的是非静态的,那么获得锁是对象,如果是静态的,那么获得锁是类,最后导致获得所有对象的锁。

锁的升级和对比

锁一共有四种状态:

  1. 无锁
  2. 偏向锁
  3. 轻量级锁
  4. 重量级锁

锁的升级

锁可以升级,但是不能降级。

这样的规则目的是为了提高获得锁和释放锁的效率。

偏向锁

作用

大多数情况下不存在锁的竞争,为了降低同一线程获得锁的开销,就在锁的对象头中加入这一线程的ID,这样,在之后这个线程进入和退出同步块的时候就不需要CAS操作来实现加锁和解锁。

撤销

当出现锁的竞争,持有偏向锁的线程才会释放锁,锁就会升级。

轻量级锁

作用

利用CAS算法,线程通过自旋的方式获取锁。这样,线程不会被阻塞。

加锁

首先JVM在线程的栈帧中创建锁记录存储空间,然后把锁对象头重的Markword复制到栈帧中。在通过利用CAS方法将锁对象的markword替换为指向线程栈帧锁记录的指针。如果成功替换,就获得了当前锁,如果已经被其他线程替换了,那么就会自旋获取锁。

解锁

将栈帧的markword再利用CAS放回对象的头中,如果失败,就说明存在锁竞争,锁就会升级为重量级锁。

锁的比较

synchronized使用

修饰方法和代码块

修饰方法很简单,就在方法前面加一个synchronized关键字。

  1. public synchronized void method()
  2. {
  3. // todo
  4. }
  5. public void method()
  6. {
  7. synchronized(this) {
  8. // todo
  9. }
  10. }

指定给某个对象加锁

  1. public void method3(SomeObject obj)
  2. {
  3. //obj 锁定的对象
  4. synchronized(obj)
  5. {
  6. // todo
  7. }
  8. }

上面的代码中,通过synchronized 给obj对象加锁。当其他线程想要访问obj,就会被阻塞。

  1. class Test implements Runnable
  2. {
  3. private byte[] lock = new byte[0]; // 特殊的instance变量
  4. public void method()
  5. {
  6. synchronized(lock) {
  7. // todo 同步代码块
  8. }
  9. }
  10. public void run() {
  11. }
  12. }

如果只是想要一个锁,可以利用特殊的实例来充当锁。

修饰静态的方法

  1. public synchronized static void method() {
  2. // todo
  3. }

因为静态方法是属于这个类的, 而不是实例化的对象,所以,synchronized 修饰的是静态方法锁定的这个类的所有对象。

修饰类

  1. class ClassName {
  2. public void method() {
  3. synchronized(ClassName.class) {
  4. // todo
  5. }
  6. }
  7. }

和修饰静态方法一样,所有对象都共有这把类锁。

参考: link.

Java并发编程的艺术(三)——synchronized的更多相关文章

  1. Java并发编程的艺术(三)——volatile

    1. 并发编程的两个关键问题 并发是让多个线程同时执行,若线程之间是独立的,那并发实现起来很简单,各自执行各自的就行:但往往多条线程之间需要共享数据,此时在并发编程过程中就不可避免要考虑两个问题:通信 ...

  2. Java并发编程的艺术(六)——线程间的通信

    多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...

  3. 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结

    <Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...

  4. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  5. Java并发编程的艺术,解读并发编程的优缺点

    并发编程的优缺点 使用并发的原因 多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升. 在特殊的业务场景下先天的就适合于并发编程. 比如在 ...

  6. 读书笔记之《Java 并发编程的艺术》

    一.多线程语义 即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,所以 CPU 通过不停的切换线程执行. 并发执行 ...

  7. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  8. java并发编程的艺术(一)---锁的基本属性

    本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...

  9. 《Java并发编程的艺术》留给自己以后看的笔记

    <Java并发编程的艺术>这本书特别好,和<深入了解JAVA虚拟机>有一拼,建议做java的都看看,下面全部都是复制书中的部分内容,主要目的是做个笔记,方便以后遇到问题能找到. ...

  10. Java并发编程的艺术 记录(一)

    模拟死锁 package com.gjjun.concurrent; /** * 模拟死锁,来源于<Java并发编程的艺术> * @Author gjjun * @Create 2018/ ...

随机推荐

  1. 对App应用架构搭建的一些思考

    当下随着App开发技术的越来越成熟,多人协同开发必不可少,一个团队中每个人的代码风格.技术栈都存在差异,因此统一一套成熟的开发架构必不可少,可以提高开发效率.统一代码风格.为项目维护提供便利. 当下A ...

  2. 两种不同的扩展Scrum的方式

    两种不同的扩展Scrum的方式 1.LeSS和LeSS Huge –大型Scrum LeSS(和LeSS Huge –真正的大型程序)的合著者Craig Larman首先批评了管理,开发人员和客户传统 ...

  3. php(tp5)生成条形码

    因为公司业务需要,研究了一下条形码 1.下载barcodegen扩展包 官网地址:https://www.barcodebakery.com 2.下载完后解压至 extend 文件夹里面,然后复制以下 ...

  4. 还不懂Java高并发的,建议看看这篇阿里大佬的总结,写的非常详细

    前言 进程是计算机中程序关于某几何数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位.是操作系统结构的基础 线程可以说是轻量级的进程,是程序执行的最小单位,使用多线程而不用多进程去进行并发程 ...

  5. zabbix 监控域名证书到期时间!!!!

    在客户端机器上创建脚本 vim /etc/zabbix/zabbix_agentd.d/check-cert-expire.sh #!/bin/sh host=$1port=$2end_date=`o ...

  6. 蓝桥杯——分组比赛(2017JavaB组第3题)

    分组比赛(17JavaB3) 9名运动员参加比赛,需要分3组进行预赛. 有哪些分组的方案呢? 标记运动员为 A,B,C,... I 下面的程序列出了所有的分组方法: ABC DEF GHI ABC D ...

  7. Mac 安装Homebrew慢的问题解决

    一开始安装,在官网上的命令: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma ...

  8. 面试官问Linux下如何编译C程序,如何回答?为你编译演示

    文章来源:嵌入式大杂烩 作者:ZhengNL Windows下常用IDE来编译,Linux下直接使用gcc来编译,编译过程是Linux嵌入式编程的基础,也是嵌入式高频基础面试问题. 一.命令行编译及各 ...

  9. java类,函数传参

    1 package 传参练习; 2 //学生姓名组成的数组:指定区间和查找的名字返回此人是否存在(如果存在返回位置否则-1) 3 public class test1 { 4 public stati ...

  10. centOs7.5.64之前的操作系统搭建GitLab记录

    GitLab搭建步骤: 1. Install and configure the necessary dependencies (1)yum install curl openssh-server o ...