什么是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关键字。

public synchronized void method()
{
// todo
} public void method()
{
synchronized(this) {
// todo
}
}

指定给某个对象加锁

public void method3(SomeObject obj)
{
//obj 锁定的对象
synchronized(obj)
{
// todo
}
}

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

class Test implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
public void method()
{
synchronized(lock) {
// todo 同步代码块
}
} public void run() { }
}

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

修饰静态的方法

public synchronized static void method() {
// todo
}

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

修饰类

class ClassName {
public void method() {
synchronized(ClassName.class) {
// todo
}
}
}

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

参考: 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. Electron 的断点续下载

    最近用 Electron 做了个壁纸程序,需要断点续下载,在这里记录一下. HTTP断点下载相关的报文 Accept-Ranges 告诉客户端服务器是否支持断点续传,服务器返回 Content-Ran ...

  2. java实现 阿拉伯数字转换为汉字数字(转载)

    public class VedioExtractSpeech { public static void main(String[] args) { System.out.println(" ...

  3. 精尽 MyBatis 源码分析 - 整体架构

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  4. 即时编译器 (JIT) 详解

    最近听我的导师他们讨论Java的即时编译器(JIT),当时并不知道这是啥东西,所以就借着周末的时间,学习了一下! 一.概述 在部分的商用虚拟机(Sun HotSpot)中,Java程序最初是通过解释器 ...

  5. Python 调用Get接口

    import requests,jsonurl = 'http://localhost:30627/api/jobs/GetNuberId?id=2'req = requests.get(url)re ...

  6. 记php多张图片 合并生成竖列 纵向长图(可用于商品详情图合并下载)

    <?php namespace app\mapi\common\image; /** * 拼接多幅图片成为一张图片 * * 参数说明:原图片为文件路径数组,目的图片如果留空,则不保存结果 * * ...

  7. Fruity Granulizer合成器功能简介

    本章节采用图文结合的方式给大家介绍电音编曲软件-FL Studio的插件Fruity Granulizer合成器,感兴趣的朋友可以一起沟通交流. Fruity Granulizer合成器是一个使用了粒 ...

  8. 【性能测试】【locust】快速入门

    简介 locust是一个开源的分布式用户负载压力测试工具,对网站(其他系统,例如接口等)进行负载测试,并确定可以处理多少的并发用户,locust特点利用了协程支持,达到高数量级别的并发,以及基于事件驱 ...

  9. Hadoop优化之数据压缩

    bBHadoop数据压缩 概述 运行hadoop程序时,I/O操作.网络数据传输.shuffle和merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下,这个时候,使用数据压缩可以提高效率 ...

  10. 自学linux——1.VMware的安装及VM下centos的安装

    1.CentOS下载 网址:https://www.centos.org/download/ 网盘:https://pan.baidu.com/s/1HrtK6xNig6KC8oh6O-6fyg 提取 ...