首页
登录 | 注册

Java多线程——sychronized

概述

关键字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)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

Java多线程——sychronized

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

Java多线程——sychronized

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

Java多线程——sychronized

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

Java多线程——sychronized

更多例子参考: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文件:

Java多线程——sychronized

  箭头指向出,从上到下分别是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 程序员到了必须掌握 Spring Boot 的时候?
    Spring Boot 2.0 的推出又激起了一阵学习 Spring Boot 热,就单从我个人的博客的访问量大幅增加就可以感受到大家对学习 Spring Boot 的热情,那么在这么多人热衷于学习 Spring Boot 之时,我自己也在 ...
  • final关键字可用于修饰类.方法和变量,final修饰的类不能被继承:final修饰的方法不可被重写:final修饰的变量不可被改变. 1. final类 final修饰的类不能被继承意思是final修饰的类不可以有子类,java.lan ...
  • java中常见的集合类大部分是非线程安全的,在多线程情况下会报并发修改异常(ConcurrentModificationException) 并发下的ArrayList类: 1 //集合类不安全的例子 2 public class Coll ...
  • java游戏开发杂谈
    线程,让游戏拥有了动态变化的能力. java的图形界面,在启动的时候,就开始了一个线程. 这个线程负责处理:JFrame.JPanel等的绘制.事件处理. 它是由操作系统调用的,在程序启动时开启,程序关闭时消亡. 这个线程里执行的逻辑,支撑 ...
  • 最近老师老是不讲新课,好繁!!! 还是来说抽象类吧. public abstract class A{ //因为下边有一个抽象方法,所以这就必须要是一个抽象类,要不然编译不能通过 public void c(){ System.out.pr ...

2019 cecdns.com webmaster#cecdns.com
12 q. 0.089 s.
京ICP备10005923号