1、为什么设计成单例模式?
保证类在内存中只有一个对象。例如:(Runtime类)。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
2、单例模式设计的3种方式:
1、饿汉式(推荐使用)
public class Singleton {
// 1,私有构造函数,不能创建对象
private Singleton() {
}
// 2,创建本类对象,定义static是为了可以使用 类名.方法 调用,定义private是为了不让其他类访问修改。
private static Singleton s = new Singleton();
// 3,对外提供公共的访问方法,定义static可以使用 类名.方法 调用,定义public为了让其他类调用。
public static Singleton getInstance() {
return s;// 返回这个对象
}
public static void print() {
System.out.println("abc");
}
}
注意:饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。
2、懒汉式(存在多线程访问问题,不建议使用)
public class Singleton {
//1,私有构造函数,不能创建对象
private Singleton(){}
//2,创建本类对象,定义static是为了可以使用 类名.方法 调用,定义private是为了不让其他类访问修改。
private static Singleton s = null;
//3,调用的时候判断。
public static Singleton getInstance() {
if(s == null){
//可能存在 线程1,线程2 同时创建的问题
s = new Singleton();
}
return s;
}
public static void print() {
System.out.println("abc");
}
}
注意:如果你想使用饿汉式,又想线程同步,可以加上同步锁。
例如:
//在方法上加同步锁
public static synchronized Singleton getInstance() {
if(s == null){
s = new Singleton();
}
return s;
}
//或者,这样双重检查锁定
public static Singleton getInstance() {
//先检查实例是否存在,如果不存在才进入下面的同步块
if(s == null){
//同步块,线程安全的创建实例
synchronized (Singleton.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(s == null){
s = new Singleton();
}
}
}
return s;
}
3、使用final修饰
class Singleton {
private Singleton() {}
//final是最终的意思,被final修饰的变量不可以被更改
public static final Singleton s = new Singleton();
}
备注:其实这种方式和饿汉式类似,都是开始就创建了一个对象实例
3、饿汉式和懒汉式区别:
饿汉式优点:
天生就是线程安全的
在第一次调用时速度也会更快,因为其资源已经初始化完成
饿汉式缺点:
会占据一定的内存
懒汉式优点:
会节省一点内存
懒汉式缺点:
线程不安全,如果加同步syncronized的也会影响性能
第一次使用的时候才new,会出现一些加载延迟,特别是需要加载的资源比较多的时候