概述

关键字synchronized的作用是实现线程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性。

  1. 直接作用于实例方法(普通同步方法):对当前实例加锁,进入同步代码前要获得当前实例的锁。

    public synchronized void test() {...}

    该操作等价于在方法体前后包装了一个synchronized(this),或者说给当前类所在对象加上了锁对象。

  2. 直接作用于静态方法(静态同步方法):对当前类加锁(当前类的Class对象),进入同步代码前要获得当前类的锁。

    public synchronized static void test() {...}

    这个锁操作等价于锁住了当前类的class对象,比如这个类叫作A,那么相当于执行了synchronized(A.class)操作。

synchronized主要就是这两种方式,其余的操作方式都是在这个基础上衍生出来的。例如“代码块加锁”:

synchronized (Object) {
...;
}

锁住的其实并不是代码块,而是object这个对象,因此在其他代码中也发生synchronized(object)时就会发生互斥。

其实synchronized(this)也是用这样的方式衍生出来的,只是在方法前面增加synchronized与之有一个区别,就是它的粒度并不是在方法级别,而是在某个指定的代码块级别。

除了用于线程同步、确保线程安全外,synchronized还可以保证线程间的可见性和有序性:

  • 可见性:从可见性角度讲,synchronized可以完全代替volatile的功能。
  • 有序性:被synchronized限制的多线程是串行执行的,限制每次只有一个线程可以访问同步块。

举几个例子

  1.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

  2.当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

  3.当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其他sychronized(this)同步代码块的访问将阻塞。

  4.第三个例子也可以用synchronized方法来实现。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。(方法m4t2xx的synchronized关键字可以在public后,也可以在public前)

更多例子参考:http://www.cnblogs.com/skywang12345/p/3479202.html

原理

在JVM规范中可以看到 synchronized 在 JVM 里的实现原理,JVM 基于进入和退出 Monitor 对象来实现方法同步和代码块同步,不过两者的实现细节不一样。

代码块同步是使用 monitorenter 和 monitorexit 指令实现的,而方法同步是使用另外一种方式实现的,细节在 JVM 规范里并没有详细说明。

monitorenter指令在编译后插入到同步代码块的开始位置,而 monitorexit 插入到方法结束处和异常处,JVM 保证每个 monitorenter 必有对应的 monitorexit 与之匹配。

  关于monitor指令:

public class Test2 {
private static Object lock = new Object();
public static void main(String[] args) {
int i = 0;
synchronized(lock) {
i++;
}
}
}

  终端中编译,然后javap反编译class文件:

  箭头指向出,从上到下分别是Enter the monitor associated with object; Exit the monitor associated with object; Be sure to exit monitor;

  其中红框处,表示 i++ 的指令,iinc 1,1:将第1个slot所在的int类型的本地变量加1;aload_2:将第2个slot所在的本地变量推到栈顶

任何对象都有一个 monitor 与之关联,当且一个 monitor 被持有后,它将处于锁状态。线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的所有权,即尝试获取对象的锁。

所以说一个对象只有一把锁。

synchronized用的锁是存在Java对象头里的,关于Java对象头:JVM——深入分析对象的内存布局

参考资料

[1] javap命令. Java特种兵, 3.2.1-javap命令工具

[2] synchronized原理. Java并发编程的艺术, 2.2-synchronized的实现原理与应用

[3] synchronized概念. 实战Java高并发程序设计, 2.7-线程安全的概念与 synchronized

Java多线程——sychronized的更多相关文章

  1. java 多线程 一个博客

    http://blog.csdn.net/a352193394/article/category/2563875 Java多线程之~~~线程安全容器的非阻塞容器 在并发编程中,会经常遇到使用容器.但是 ...

  2. Java多线程编程核心技术

    Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...

  3. Java多线程:生命周期,实现与调度

    Java线程生命周期 Java线程实现方法 继承Thread类,重写run()方法 实现Runnable接口,便于继承其他类 Callable类替换Runnable类,实现返回值 Future接口对任 ...

  4. Java多线程:synchronized的可重入性

    从Java多线程:线程间通信之volatile与sychronized这篇文章中我们了解了synchronized的基本特性,知道了一旦有一个线程访问某个对象的synchronized修饰的方法或代码 ...

  5. Java多线程:线程间通信之Lock

    Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...

  6. java多线程中的三种特性

    java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...

  7. Java多线程面试题整理

    部分一:多线程部分: 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. ...

  8. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  9. Java多线程系列——从菜鸟到入门

    持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...

随机推荐

  1. git web开发版本管理

    使用git来管理web开发: 我们需要做的事情 : 1,在服务器建立版本仓库: 2,在服务器建立稳定版本的站点,编写版本仓库的hooks: 3,在开发服务器上提交开发版本: 下面一步一步来:(注意建立 ...

  2. 微信图片分享遇到 checkArgs fail, thumbData is invalid

    该问题主要是微信图片限制32K以内的原因,可将bmpToByteArray方法进行进行改写. 原方法是: /** * 得到Bitmap的byte * @author netcorner * @para ...

  3. Python 文件 seek() 方法

    概述 Python 文件 seek() 方法用于移动文件读取指针到指定位置. 语法 seek() 方法语法如下: fileObject.seek(offset[,whence]) 参数 offset  ...

  4. struts系列:校验(三)国际化

    一.设置国际化资源标识 struts可以通过request_locale参数来进行国际化参数设置 例如页面可以通过如下链接完成语言切换: <s:a href="locale.actio ...

  5. tomcat启动报错 java.lang.ClassNotFoundException: org.apache.jsp.index_jsp

    项目运行一直很平稳,但是换了tomcat之后打开jsp网页时就报错,描述如下: 1. 错误描述 打开jsp网页时报错 java.lang.NullPointerException     org.ap ...

  6. PHP实现JS的无符号右移(>>>)

    举例: JS: 5>>>2 PHP function uright($a, $n) { $c = 2147483647 >> ($n - 1); return $c &a ...

  7. Thrift 简单实现C#通讯服务程序 (跨语言 MicroServices)

    Thrift是一种可伸缩的跨语言服务框架,它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,工作效率和无缝地与C++,C#,Java,Python和PHP和Ruby结合.thrift允许你定义一个 ...

  8. ios Coredata 关联 UITableView 数据自动更新

    昨天写了一篇关于coredata的文章,自己觉得挺傻的文章.没想其它程序员看过后觉得更傻,于是今天决定写一篇厉害点的,首先写了一个coredata和uitableview结合的框架,非常简单实现了数据 ...

  9. django——文件上传_分页_ajax_富文本_celery

    上传文件 概述 当Django在处理文件上传时,文件的数据被存储在request.FILES属性中 FILES只有在请求的方法为POST且提交的form表单带有enctype="multip ...

  10. golang gc 优化思路以及实例分析

    一个即将上线的go 写的高频服务,压测的时候发现 gc 特别高,高到10%-15% 左右了,本文记录下优化 gc 的过程和和思路.线上环境1.10. 首先,查看gc 是否有异常,我们可以使用 gctr ...