Java多线程——sychronized
概述
关键字synchronized的作用是实现线程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性。
直接作用于实例方法(普通同步方法):对当前实例加锁,进入同步代码前要获得当前实例的锁。
public synchronized void test() {...}该操作等价于在方法体前后包装了一个synchronized(this),或者说给当前类所在对象加上了锁对象。
直接作用于静态方法(静态同步方法):对当前类加锁(当前类的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的更多相关文章
- java 多线程 一个博客
http://blog.csdn.net/a352193394/article/category/2563875 Java多线程之~~~线程安全容器的非阻塞容器 在并发编程中,会经常遇到使用容器.但是 ...
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- Java多线程:生命周期,实现与调度
Java线程生命周期 Java线程实现方法 继承Thread类,重写run()方法 实现Runnable接口,便于继承其他类 Callable类替换Runnable类,实现返回值 Future接口对任 ...
- Java多线程:synchronized的可重入性
从Java多线程:线程间通信之volatile与sychronized这篇文章中我们了解了synchronized的基本特性,知道了一旦有一个线程访问某个对象的synchronized修饰的方法或代码 ...
- Java多线程:线程间通信之Lock
Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
- Java多线程面试题整理
部分一:多线程部分: 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- Java多线程系列——从菜鸟到入门
持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...
随机推荐
- 【colaboratory】在colab中安装mxnet
在学习<动手学深度学习>内容是,该内容用的是mxnet框架,在电脑本地安装过程中又容易出现错误,怎么也安装不上,所有的条件都尝试了. 汗颜,指的另谋他法. 只有在谷歌的学习平台上安装使用h ...
- idea13注册机
public class Keygen { /** * @param s * @param i * @param bytes * @return */ public static short getC ...
- Nginx错误提示:504 Gateway Time-out解决方法
朋友说504 Gateway Time-out的错误提示与nginx本身是没有任何关系的我们可以通过fastcgi配置参数的调整进行解 决. 修改 php-fpm 配置文件: 1.把 max_chil ...
- Python 文件 fileno() 方法
描述 Python 文件 fileno() 方法返回一个整型的文件描述符(file descriptor FD 整型),可用于底层操作系统的 I/O 操作. 语法 fileno() 方法语法如下: f ...
- 【转】Oracle回收站(recyclebin)
我们都比较熟悉windows中的回收站,文件删除后放到回收站里还可以再复原.Oracle回收站的原理完全一样,只是实现的细节方面有些差异.另外回收站中只能回收表和相关的对象包括索引.约束.触发器.嵌套 ...
- getenv()函数
在PHP中getenv(参数)函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量,具体如下: “PHP_SELF” 当前正在执行脚本的文件名,与document root 相关 ...
- 永久代 PermGen 简述
永久代(PermGen) 绝大部分 Java 程序员应该都见过 “java.lang.OutOfMemoryError: PermGen space “这个异常.这里的 “PermGen space” ...
- Java批量插入更新操作
以前总是说批量插入和更新的效率比非批量的要高,但是一直没有使用过批量处理数据的功能,现在由于项目中需要处理的数据量比较大,所以使用了批量处理的功能,java代码如下: 1.java实现批量插入数据: ...
- category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性
属性 其实就是get/set 方法.我们可以使用 objc_setAssociatedObject/objc_getAssociatedObject 实现 动态向类中添加 方法 @interfac ...
- How to fix ERR_SSL_VERSION_INTERFERENCE on Chrome?
https://ugetfix.com/ask/how-to-fix-err_ssl_version_interference-on-chrome/ Question Issue: How to fi ...