前言


在上一篇文章中咱们讲到实现了一个数值序列生成器

然而在咱们的多线程的环境下,会发现生成的数值序列不是咱们所预期的那种递增的序列,而是会呈现那种咱们所不预期的谬误

过后的解决方案比较简单,就在那个办法上加了一个synchronized,于是这个问题就解决了,咱们并没有去具体的解释为什么在办法上加了一个synchronized就可能解决

从本篇文章开始,咱们来正式的理解解决线程安全性问题的各种的计划,首先第一个就是synchronized,咱们前面还会学习其余的锁呀、包含咱们的元子类等等

一、内置锁


在看synchronized之前,咱们首先来看内置锁,什么是内置锁呢

就是说Java中每一个对象都能够用作同步的锁,那么这些锁就被称之为内置锁

咱们应用代码领会领会内置锁是什么意思?

public class Sequence {    int value;    public synchronized  int getNext(){        return  value++;    }    }

咱们说每一个Java中的对象都是一个内置锁,当这个线程在进入同步代码块之前,都必须先取得锁也就是取得内置锁,而后取得锁之后就能够进入到同步代码块中执行

而咱们的synchronized放在办法上,也就是说实例办法一般办法上,那么内置锁也就是所谓的对象锁,就是以后类的实例

public class Sequence {    /**     * synchronized 放在一般办法上,默认内置锁是以后实例     * @return     */    public synchronized  int getNext(){        return  value++;    }    }

而其余的线程再想进来,那么就必须期待,于是这个线程开始往下执行,咱们之前也都翻译过了,value++是执行了好多的字节码指令,那么,等字节码指令执行结束之后,这个线程就能够开释掉锁了,把它拿到的锁开释掉

这个synchronized它除了能用在办法上以外,它还能用润饰静态方法,也就是类的办法

public class Sequence {    private static int value;    /**     * synchronized 放在静态方法上,内置锁是以后的Class字节码对象     * @return     */    public static synchronized int getPrevious(){        return value --;    }    }

同时它除了润饰办法以外它还可能润饰代码块,咱们能够举个例子应用同步代码块来润饰它

public class Sequence {    public int getValue(){        synchronized (Integer.valueOf(value)){                    }        if(value>0){            return value;        }else{            return  -1;        }    }}

万物皆对象,你只有这里指定一个对象,那么,就能够作为一把锁

其实synchronized的原理其实就是加了锁,内置锁和互斥锁所决定的。每个对象都有锁,而这些锁都是互斥的,一个进来之后,另外的就不能进来了,因而就能够保障线程的安全性

二、字节码查看synchronized


那么在从字节码层面,在Java虚拟机标准中,能够看到,synchronized在Java虚拟机中执行同步代码块的时候,其实它是基于进入和退出monitor对象来实现办法同步的

咱们能够观看字节码指令查看该Sequence.class的同步代码块局部

发现在第4行就是monitorenter进入执行,执行到第17行就退出

而当咱们个别编写if-else时就会遇到goto,同时会跳到相应的操作并也开释锁

参考资料


龙果学院:并发编程原理与实战(叶子猿老师)