面试中关于synchronized关键字

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;
}
}
   另外,须要注意uniqueInstance采用volatile关键字修饰颇有必要。
    uniqueInstance采用volatile关键字修饰颇有必要,uniqueInstance = new SingIeton();这段代码实际上是分为三步执行:
    1.为uniqueInstance分配内存空间
    2.初始化uniqueInstance
    3.将uniqueInstance指向分配的内存地址
  可是因为JVM具备指令重排的特性,执行顺序可能1.3.2。 指令重排在单线程环境下不会出问题,可是在多线程环境下会致使一个线程得到尚未初始化的实例。例如,线程T1执行了1和3,此时T2调用getUniqueInstance()后发现uniqueInstance不为空,所以返回uniqueInstance,但此时uniqueInstance还未被初始化。使用volatile能够禁止JVM的重排序,保证多线程环境下也能正常运行
 
3、讲一下 synchronized 关键字的底层原理
 synchronized 关键字底层原理属于 JVM 层面。
  ① synchronized 同步语句块的状况
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 方法");
}
}
synchronized 修饰的方法并无 monitorenter 指令和 monitorexit 指令,取得代之的却 是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法, JVM 经过该 ACC_SYNCHRONIZED 访问标志来 辨别一个方法是否声明为同步方法,从而执行相应的同步调用。
相关文章
相关标签/搜索