概述

关键字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. 小而美的ghost driver

    做过selenium自动化项目的同学应该都遇到过这样的问题:测试用例太多,运行速度过慢导致团队成员怨声载道. 于是便有了selenium grid和多线程运行selenium测试用例的方法.这些方法各 ...

  2. pthread编译时报错的解决方法

    最近在学习POSIX thread编程,今天编译一个程序报如下错误: /tmp/ccXH8mJy.o:在函数‘main’中:deadlock.c:(.text+0xbb):对‘pthread_crea ...

  3. [转]Intellij IDEA快捷键与使用小技巧

    Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Shift+Click,可以关闭文件Ctrl+[ ...

  4. Cadence 5141 下TSMC 05U工艺库安装

    以下资料摘自:<T13RF PDK簡介>-張文旭 观念与TSMC工艺库的安装 管理者安裝TSMC 0.13 MS/RF的環境下之PDK的安裝方式相當容易,首先以root的方式進入Unix/ ...

  5. django -- 对模式进行调式(pay with the api)

    在django中如果想对models进行调试.不用每次都要runserver 在web界面上点点点.django自己带了字符界面的调试功能 一.完成app的注册.与models的定义: 注册app: ...

  6. 引文分析工具HistCite使用简介

    运行环境: win8.1(lenovo Y450) 1.去www.histcite.com下载histcite最新版,并安装 2.去WOS下载文献.保存方式为: 记录数: 记录1至500(最大支持50 ...

  7. dd-wrt 中继配置

    本配置方法在tp-link 703n v1.6上应用成功 1.首先把703n刷成dd-wrt.这里我刷的是 DD-WRT v24-sp2 (03/15/12) std版本,要刷两个固件,一个facto ...

  8. javascrip json2

    http://www.json.org/json-zh.html 下载: https://github.com/douglascrockford/JSON-js

  9. gf框架之grpool - 高性能的goroutine池

    Go语言中的goroutine虽然相对于系统线程来说比较轻量级,但是在高并发量下的goroutine频繁创建和销毁对于性能损耗以及GC来说压力也不小.充分将goroutine复用,减少goroutin ...

  10. FFmpeg(12)-使用NDK通过GLSurfaceView完成视频的播放

    一.包含头文件和库文件 这里采用的是NDK中的ANativeWindow来完成视频的播放,因为需要添加相关的库和头文件. CMakeLists target_link_libraries( # Spe ...