单例模式
饿汉式(静态常量)
/**
* @Author: Antares
* @Date: 2020/2/21 22:22
*/
public class Single01 {
public static void main(String[] args) {
SingleTon instance01 = SingleTon.getInstance();
SingleTon instance02 = SingleTon.getInstance();
System.out.println(instance01 == instance02);
}
}
class SingleTon{
/**
* 构造私有化,外部new
*/
private SingleTon(){
}
/**
* 本类内部创建对象实例
*/
private final static SingleTon instance = new SingleTon();
/**
*
* @return instance
*/
public static SingleTon getInstance() {
return instance;
}
}
饿汉式(静态代码块)
/**
* @Author: Antares
* @Date: 2020/2/21 22:40
*/
public class SingleTon02 {
public static void main(String[] args) {
SingleTon instance01 = SingleTon.getInstance();
SingleTon instance02 = SingleTon.getInstance();
System.out.println(instance01 == instance02);
}
}
class SingleTon{
/**
* 构造私有化,外部new
*/
private SingleTon(){
}
/**
* 本类内部创建对象实例
*/
private static SingleTon instance ;
// 静态代码块中创建单例对象
static {
SingleTon instance = new SingleTon();
}
/**
*
* @return instance
*/
public static SingleTon getInstance() {
return instance;
}
}
优点: 写法简单,在类装载时实例化,避免了线程同步问题
缺点: 在类装载时实例化,没有达到Lazy Loading的效果.如果从始至终没有使用过这个类,会造成内存里浪费
结论: 这种单例模式可用,可能造成内存浪费
懒汉式(线程不安全)
/**
* @Author: Antares
* @Date: 2020/2/21 22:52
*/
public class SingleTon03 {
public static void main(String[] args) {
SingleTon instance01 = SingleTon.getInstance();
SingleTon instance02 = SingleTon.getInstance();
System.out.println(instance01 == instance02);
}
}
class SingleTon{
private static SingleTon instance;
private SingleTon() {
}
/**
* 提供一个静态公有方法,当使用到该方法时,才去创建instance
* 即懒汉式
*/
public static SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
}
优点: 起到了Lazy Loading 的效果,但是只能在单线程下使用
缺点: 如果在多线程下.一个线程进入if,还没来得及往下执行,另一个线程也通过了这个判断语句,这时候会出现多个实例
结论: 在实际开发中,不能使用这种方式
懒汉式(线程安全,同步方法)
public static synchronized SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
解决了线程不安全问题,但是效率太低
结论: 可用,不推荐
懒汉式(线程安全,同步代码块)
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
instance = new SingleTon();
}
}
return instance;
}
本意是解决效率低,但是这种同步不能起到线程同步作用
结论: 不能用
双重检查
/**
* 提供一个静态公有方法,当使用到该方法时,加入双重检查才去创建instance
* 即懒汉式
*/
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
instance = new SingleTon();
}
}
return instance;
}
Double Check 概念是多线程开发中经常用到的,线程安全,延迟加载,效率较高
结论: 开发中经常使用
静态内部类
/**
* @Author: Antares
* @Date: 2020/2/21 23:13
*/
public class SingleTon07 {
public static void main(String[] args) {
SingleTon instance01 = SingleTon.getInstance();
SingleTon instance02 = SingleTon.getInstance();
System.out.println(instance01 == instance02);
}
}
class SingleTon{
private static volatile SingleTon instance;
private SingleTon() {
}
private static class SingleTonInstance {
private static final SingleTon INSTANCE = new SingleTon();
}
/**
* 提供一个静态公有方法,当使用到该方法时,加入双重检查才去创建instance
* 即懒汉式
*/
public static SingleTon getInstance() {
return SingleTonInstance.INSTANCE;
}
}
这种方式采用了类加载的机制来保证初始化实例时只有一个线程
类的静态属性只会在第一次加载时初始化,保证了线程的安全性
结论: 推荐使用
枚举
/**
* @Author: Antares
* @Date: 2020/2/21 23:14
*/
public class SingleTon08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance01 = Singleton.INSTANCE;
System.out.println(instance == instance01);
}
}
enum Singleton {
INSTANCE;
public void sayOK() {
System.out.println("ok");
}
}
不仅避免了多线程同步问题,而且还能防止反序列化,重新创建对象
结论: 推荐使用
单例模式保证了系统内存中该类只存在一个对象,节省资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
单例模式使用的场景:需要频繁的进行创建和销毁的对象,创建对象时好事时多时少或耗费资源过多(重量级的对象,但又经常用到的额对象,工具类对象,频繁访问数据库或文件的对象
javalang.RunTime就是经典的单例模式