概述
单例设计模式要点:
一是某个类只能有一个实例;
构造器私有化
二是它必须自行创建这个实例;
含有一个该类的静态变量来保存这个唯一的实例
三是它必须自行向整个系统提供这个实例;
对外提供获取该实例对象的方式:
(1)直接暴露(2)用静态变量的get方法获取
常见的几种形式:
饿汉式:直接创建对象,不存在线程安全问题
直接实例化饿汉式(简洁直观)
枚举式(最简洁)
静态代码块饿汉式(适合复杂实例化)
懒汉式:延迟创建对象
线程不安全(适用于单线程)
线程安全(适用于多线程)
静态内部类形式(适用于多线程)
代码示例:
1.直接实例化饿汉式
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1(){
}
}
2.枚举式
public enum Singleton2 {
INSTANCE
}
3.静态代码块饿汉式(适合复杂情况,静态代码块中还可以写其他业务)
public class Singleton3 {
public static final Singleton3 INSTANCE;
static{
INSTANCE = new Singleton3();
}
private Singleton3(){
}
}
以上的创建方式,调用时都是在main方法中直接用类名.(点)的形式即可,比如
Singleton3 singleton3 = Singleton3.INSTANCE;
**总结:**饿汉式不存在线程安全问题,这是由其类加载机制来保证的。
饿汉式的问题:有可能程序运行时并不需要对象,这样的话,使用饿汉式创建会影响效率,占用资源。于是就有了懒汉式(饱汉式)
以下是懒汉式设计方法:
1.线程不安全(适用于单线程)
//在方法中去new一个对象,调用方法的时候才会创建对象
public class Singleton4 {
private static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if(instance == null){
instance = new Singleton4();
}
return instance;
}
}
接着写一个测试方法:
public class Test{
public static void main(String[] args) {
Singleton4 s1 = Singleton4.getInstance();
Singleton4 s2 = Singleton4.getInstance();
System.out.println(s1==s2);
System.out.println(s1);
System.out.println(s2);
}
}
输出结果,单线程下线程安全
那么如果在多线程情况下,结果会怎么样呢,这时,我们创建一个多线程环境下的测试用例:
public class TestSingleton {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//多线程情况下
Callable<Singleton4> c = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};
//创建线程池
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = es.submit(c);
Future<Singleton4> f2 = es.submit(c);
Singleton4 s1 = f1.get();
Singleton4 s2 = f2.get();
System.out.println(s1==s2);
System.out.println(s1);
System.out.println(s2);
es.shutdown();
}
}
同时,在Singleton4中的instance = new Singleton4();上方加上一个休眠时间
Thread.sleep(1000);//测试多线程下的线程安全问题
运行得到如下结果:
说明了线程存在安全问题,不适用于多线程,下面我们想办法将其修改处线程安全的
2.线程安全(适用于多线程)
只需要在上一步的Singleton4类中的getInstance()方法加上一个synchronized同步块即可
public class Singleton5 {
private static Singleton5 instance;
private Singleton5(){
}
public static Singleton5 getInstance(){
synchronized (Singleton5.class) {
if(instance == null){
try {
Thread.sleep(1000);//测试多线程下的线程安全问题
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton5();
}
}
return instance;
}
}
然后用同样的测试方法测试,得到如下结果:
这样就保证了线程的安全问题
3.静态内部类形式(适用于多线程)
另外一种方法,更简便
//在内部类被加载和初始化时,才创建INCATANCE实例对象
//静态内部类不会自动随着外部类的加载和初始化而初始化,他是要单独去加载和初始化的。
//因为是在内部类加载和初始化时创建的,因此线程安全的
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
public static final Singleton6 INCTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INCTANCE;
}
}
测试方法同之前
测试结果:
觉得不错的小伙伴可以右上角点个赞或关注哟!
最后
以上就是自然朋友为你收集整理的单例设计模式详解的全部内容,希望文章能够帮你解决单例设计模式详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复