1、 说说对synchronized关键字的了解java
synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字能够保证被它修饰的方法或代码块在任意时刻只能有一个线程执行。面试
另外,在早期的java版本中,synchronized属于重量级锁,效率低下,由于监视器锁(minitor)是依赖于底层的操做系统的Mutex Lock来实现的,java的线程是映射到操做系统的原生线程之上的。若是要挂起或者唤醒一个线程都须要操做系统来帮忙完成,而操做系统实现线程之间的切换时须要从用户态转换的内核态,这个状态之间的转换须要比较长的时间,因此早期的synchronized效率低下。在java 6以后java官方对从JVM层面对synchronized较大优化。java1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减小锁操做的开销。安全
2、synchronized关键字的三种使用方式:多线程
1.修饰实例方法,做用于当前对象实例加锁,进入同步代码前要得到当前对象实例的锁优化
2.修饰静态方法,做用于当前类对象加锁,进入同步代码前要得到当前类对象的锁。也就是给当前类加锁,会做用于当前类的全部对象实例,由于对象静态成员不属于任何一个实例对象,是类成员(static代表这是该类的一个静态资源,无论new了多少对象,只有一份,因此对该类的全部对象都加了锁)。因此若是一个线程A调用一个实例对象的非静态synchronized方法,而线程B须要调用这个实例对象所属类的静态synchronized方法,是容许的,不会发生互斥现象,由于访问静态synchronized方法占用的锁是当前类的锁,而访问非静态synchronized方法占用的锁是当前实例对象锁。this
3.修饰代码块,指定加锁现象,对给定对象加锁,进入同步代码块库前要得到给定对象的锁。和synchronized方法同样,synchronized(this)也是锁定当前对象的。synchronized关键字加到static静态方法和synchronized(class)代码块上都是给Class类上锁。这里再提一下:synchronized关键字加到非静态方法上是给对象实例上锁。另外须要注意的是:尽可能不要使用synchronized(String a)由于在JVM中,字符串常量池具备缓冲功能。spa
public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() { } public static Singleton getUniqueInstance() { //先判断对象是否已经实例过,没有实例化过才进入加锁代码if (uniqueInstance == null) { //类对象加锁 synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
public class SynchronizedDemo { public void method() { synchronized (this) { System.out.println("synchronized 代码块"); } } }
synchronized同步语句块的使用实现的是monitorenter和monitorexit指令,其中monitorenter指令指向同步代码块开始位置,monitorexit指令指向同步代码块的结束位置。当执行monitorenter指令时,线程试图获取锁也就是获取monitor(monitor对象存在于每一个java对象的对象头中,synchronized即是经过这种方式获取锁的,也就是java中任意对象能够做为锁的缘由)的持有权,当计数器为0则成功获取,获取后将锁计数器设为1也就是加1。相应的在执行monitorenter指令后,将锁计数器设为0,代表锁被释放。若是获取对象失败,那当前对象就要阻塞等待,知道锁被另外一个线程释放为止。操作系统
② synchronized 修饰方法的的状况线程
public class SynchronizedDemo2 { public synchronized void method() { System.out.println("synchronized 方法"); } }