目录
一、wait和sleep的区别
wait是⽤于线程之间的通信的,sleep是让线程阻 塞⼀段时间。唯⼀的相同点就是都可以让线程放弃执⾏⼀段时间。
(1)wait需要搭配synchronized使⽤,sleep不需要。
(2)wait是Object的⽅法,sleep是Thread的静态⽅法。
当有多个wait和一个notify的时候,唤醒的线程是随机的,当有多个notify和一个wait的时候,多出来的notify并不会影响进程。
二、单例模式
(1)饿汉模式:类加载的同时,创建实例。由于创建操作在加载的时候完成,所以多线程运行的时候不会有线程安全问题。
class SingleTon{
private static SingleTon instance = new SingleTon() ;
private SingleTon(){}
public static SingleTon getInstance(){
return instance;
}
}
(2)懒汉模式:类加载的时候不创建实例.第⼀次使⽤的时候才创建实例。懒汉模式不同于饿汉模式,由于不在类加载的时候创建实例,当多线程运行的时候存在几个问题。
<1>问题一:多线程运行 if 操作容易多个线程同时运行,所以很有可能同时创建了一个实例,而先创建的实力则会消失。
class SignleTonLazy{
private static SignleTonLazy instance = null;
private SignleTonLazy(){}
public static SignleTonLazy getInstance(){
if(instance == null){
instance = new SignleTonLazy();
}
return instance;
}
}
<2>问题二:我们可以在第一次if判断前加上锁来确保线程安全问题。但是这么做,会让多个线程同时进行锁的判断等待,会造成大量的时间浪费
class SignleTonLazy{
public static String loker1 = new String();
private static SignleTonLazy instance = null;
private SignleTonLazy(){}
public static SignleTonLazy getInstance(){
synchronized (loker1){
if(instance == null){
instance = new SignleTonLazy();
}
}
return instance;
}
}
<3>问题三:在我们进行if加锁之前,可以嵌套一个if做判断,如果是第一次创建实例再去进行等待。但是这么做仍然有问题,因为在创建实例的时候,JVM的优化可能让指令重排序,会造成先拿到实例地址,后进行地址赋值,这就导致拿到的 实例值是错误的,所以我们最后需要加上volatile给要创建的实例,来让JVM最小程度优化指令。
class SignleTonLazy{
public static String loker1 = new String();
private static volatile SignleTonLazy instance = null;
private SignleTonLazy(){}
public static SignleTonLazy getInstance(){
if(instance == null){
synchronized (loker1){
if(instance == null){
instance = new SignleTonLazy();
}
}
}
return instance;
}
}
创建局部变量,处于JVM内存中的“栈”区域中,new 出来变量,处于JVM内存中“堆”区中。