synchronized:
1、 说一说自己对于 synchronized 关键字的了解
synchronized关键字解决的是多个线程间访问资源的同步性,它可以保证被它修饰的方法或者代码块在任意时刻都只能有一个线程执行。
2. 说说自己是怎么使用 synchronized 关键字,在项目中用到了吗
synchronized加到static静态方法和synchronzied(class)代码块上都是给Class类加锁。
synchronzied加到实例方法和synchronized(this)代码块上都是给对象实例加锁。
3、单例模式了解吗?来给我手写一下!给我解释一下双重检验锁方式实现单例模式的原理
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 = new Singleton();这段代码其实是分三步执行:
1、为uniqueInstance分配内存空间
2、初始化 uniqueInstance
3、将uniqueInstance 指向分配的内存地址
但由于jvm具有指令重排的特性,执行的顺序可能变为为1->3->2。指令重排在单线程环境下不会出现问题。但是在多线程环境下会导致一个线程获得还没有初始化的实例。
例如,线程T1执行了1和3,此时T2调用getUniqueInstance()后发现uniqueInstance不为空,因此返回uniqueInstance,但此时uniqueInstance还未被初始化,
使用volatile可以禁止JVM的指令重排,保证在多线程环境下也能正常运行
volatile
1、 讲一下Java内存模型
在 JDK1.2 之前,Java的内存模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的。而在当前的 Java 内存模型下,
线程可以把变量保存本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,
而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
要解决这个问题,就需要把变量声明为volatile,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取(代替在寄存器中读取)。
说白了, volatile 关键字的主要作用就是保证变量的可见性,然后还有一个作用是防止指令重排序。
synchronzied和volatile关键字区别:
1、volatile解决变量在多个线程之间的可见性,synchronized解决的是多个线程之间访问资源的同步性。
2、volatile只能保证可见性,不能保证原子性,synchronized两者都能保证。
3、多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。