解释:一个类只有一个实例:即在初始化或被其他类调用的过程中,生成的或使用的都是同一个实例
实现
方法一:懒汉式单例
优点:理解简单,应用广泛
缺点:类在初始化之后就会生成一个实例,无论是否需要用到都会生成(个人感觉无伤大雅)
public class SingleTon{
private static SingleTon instance = new SingleTon();
//将构造方法设为私有,限制其他类无法通过new的方法来获取该类的实例;
private SingleTon(){}
//提出公共方法来获取该类的实例,该实例在类初始化之后进行的初始化,全局的实例化对象,也是唯一一个
public SingleTon getInstance(){
return instance;
}
}
方法二:饿汉式单例
优点:比起懒汉式单例模式,这种方法会在外部类需要获取该类的实例时才会进行初始化
缺点:在多个线程同时访问到if(INSTANCE == null)之后,new SongleTon()之前;多线程情况下会生成多个实例的情况
public class SingleTon {
private static SingleTon INSTANCE;
public static SingleTon getInstance2(){
if(INSTANCE == null){
try {
//增加休眠时间,提高在等待实例初始化的线程数
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new SingleTon();
}
return INSTANCE;
}
//增加main方法测试多个线程共同获取同一个类的实例的结果是否是一个
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->
System.out.println(SingleTon.getInstance2().hashCode())
).start();
}
}
}
方法三:饿汉式单例优化之方法加锁:
优点:解决了上诉的多线程问题
缺点:效率降低
public class SingleTon {
private static SingleTon INSTANCE;
public static synchronized SingleTon getInstance2(){
if(INSTANCE == null){
try {
//增加休眠时间,提高在等待实例初始化的线程数
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new SingleTon();
}
return INSTANCE;
}
//增加main方法测试多个线程共同获取同一个类的实例的结果是否是一个
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->
System.out.println(SingleTon.getInstance2().hashCode())
).start();
}
}
}
方法四:饿汉式单例之局部方法加锁:
缺点:还是会导致多线程情况下出现多个实例,即多个线程同时进行了if(INSTANCE == null)判断,又依次进行了同步代码块的情况
public class SingleTon {
private static SingleTon INSTANCE;
public static SingleTon getInstance2(){
if(INSTANCE == null){
synchronized(SingleTon.class){
try {
//增加休眠时间,提高在等待实例初始化的线程数
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new SingleTon();
}
}
return INSTANCE;
}
//增加main方法测试多个线程共同获取同一个类的实例的结果是否是一个
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->
System.out.println(SingleTon.getInstance2().hashCode())
).start();
}
}
}
方法五:饿汉式单例之局部方法加锁后再判断:
优点:较为完美的饿汉式单例模式,第一次判断能有效减少多线程请求时执行同步代码块的次数;第二次判断能对外部等待的线程获取实例的实时变化做监控及判断,实现了多线程情况下安全的饿汉式单例模式
缺点:代码并不简洁,就像是为了实现单例而设计的单例模式,理论应用大于实际应用
public class SingleTon {
private static SingleTon INSTANCE;
public static SingleTon getInstance2(){
if(INSTANCE == null){
synchronized(SingleTon.class){
if(INSTANCE == null){
try {
//增加休眠时间,提高在等待实例初始化的线程数
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new SingleTon();
}
}
}
return INSTANCE;
}
//增加main方法测试多个线程共同获取同一个类的实例的结果是否是一个
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->
System.out.println(SingleTon.getInstance2().hashCode())
).start();
}
}
}
方法六:静态内部类实现单例
优点:完美的单例模式之一
public class SingleTon{
private SingleTon(){}
//静态内部类不会随着JVM加载类后就被加载
private static class SingleTonHandle{
private static final SingleTon instance = new SingleTon();
}
public SingleTon getInstance(){
return SingleTonHandle.instance;
}
}
方法七:枚举实现的单例
优点:完美的单例模式之一
public enum SingleTonByEnum {
INSTANCE;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->
System.out.println(SingleTonByEnum.INSTANCE)
).start();
}
}
}