什么是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. ViewPager2与ViewPager的区别

    viewpager: viewpager有2个弊端: 1.不能关闭预加载 2.更新adapter不生效   我们在加载数据的时候,viewpager默认会帮我们预加载前后两个页面的数据,并且这2个vi ...

  2. UI自动化中无头浏览器的应用

    因为某次工作中写了个脚本要来回跑,还要在本机上做很多其他的事情,所以就上网找了个方法,无头浏览器,这样就不会浏览器来回弹出来,执行用例还会很快. 废话不多说,直接放代码: #coding=utf-8 ...

  3. Python_DOM

    Dom简介:Js通过标签筛选让html多文件联动 1.找到标签 获取单个元素 docum ent.getElemrntByID('i1') 获取多个元素(列表)document.getElemrnts ...

  4. 灵活运用的@RequestParam和@RequestBody

    最近在编写项目的过程中,老出现前后端传递参数格式不一致.不统一的问题,对于一个已经快工作一年的Java程序员来说,实属不合格,所以我就下来好好研究了一下@RequestParam和@RequestBo ...

  5. Android ContentProvider 启动分析

    对于 ContentProvider 还不是很熟悉的同学,可以阅读上一篇 Android ContentProvider 基本原理和使用详解.本文主要是对 contentProvider 的源码进行分 ...

  6. 怎么绘制C语言选择和循环语句的思维导图

    C语言是一门非常基础的计算机语言,是大部分本科学生的公共专业,在C语言的学习中,选择和循环语句是至关重要的部分,利用思维导图可以有效节约时间并加深知识点记忆. 接下来就为大家介绍一下我用iMindMa ...

  7. jmeter脚本的编写

    前几天讲到了性能测试的入门,今日继续来讲解jmeter的使用,本文讲的都是比较细,希望各位耐心的看完. 一.jmeter的安装与打开 前提条件:给大家一个jmeter的安装包  百度网盘的路径如下:链 ...

  8. windows创建隐藏用户的powershell脚本

    通过保存并重新注册已删除用户的注册表的方式来隐藏用户,未登录时登陆界面不可见,登陆后可见 方法详情见: https://www.k0rz3n.com/2018/06/26/windows%E6%B8% ...

  9. Robot Framework安装和入门

    1:安装 python 安装python并且配置好环境变量 2:安装 Robot Framework pip install robotframework 3:安装GUI界面 pip install ...

  10. 精尽MyBatis源码分析 - 插件机制

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