单例模式
1、饿汉式(静态常量)
java
@Slf4j
public class SingletonTest01 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
log.info("比对结果:{}",singleton==singleton2); //true
}
}
/**
* 饿汉式,(静态变量)
*/
class Singleton {
//1、构造器私有化,外部new
private Singleton() {
}
//本部内部类创建对象实例
private final static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
2、饿汉式(静态代码块)
也可以使用,但是稍微有点内存的浪费(并且线程是安全的)
java
@SuppressWarnings("All")
@Slf4j
public class SingletonTestStatic {
public static void main(String[] args) {
SingletonStatic singleton = SingletonStatic.getInstance();
SingletonStatic singleton2 = SingletonStatic.getInstance();
log.info("比对结果:{}",singleton == singleton2);
}
}
/**
* 饿汉式,(静态代码块)
*/
class SingletonStatic {
/**
* 1、构造器私有化,外部new
*/
private SingletonStatic() {
instance = new SingletonStatic();
}
//本部内部类创建对象实例
private static SingletonStatic instance;
public static SingletonStatic getInstance() {
return instance;
}
}
3、 懒汉式(线程不安全)
不推荐使用
java
@SuppressWarnings("All")
@Slf4j
public class SingletonHungryMan {
public static void main(String[] args) {
SingletonHungry singleton=SingletonHungry.getInstance();
SingletonHungry singleton1=SingletonHungry.getInstance();
log.info("比对结果:{}",singleton==singleton1);
log.info("singleton:hasCode:{}",singleton.hashCode());
log.info("singleton1:hasCode:{}",singleton1.hashCode());
}
}
/**
* 饿汉式,(静态代码块)
*/
class SingletonHungry {
private static SingletonHungry instance;
private SingletonHungry() {
}
//提供一个静态公有方法,当使用到该方法时候,才去创建instance
//即懒汉式
public static SingletonHungry getInstance() {
if(null==instance){
instance=new SingletonHungry();
}
return instance;
}
}
4、懒汉式(线程安全,同步方法)
java
@SuppressWarnings("All")
@Slf4j
public class SingletonHungryManSync {
public static void main(String[] args) {
SingletonHungryManSync singleton= SingletonHungrySync.getInstance();
SingletonHungryManSync singleton1= SingletonHungrySync.getInstance();
log.info("比对结果:{}",singleton==singleton1);
log.info("singleton:hasCode:{}",singleton.hashCode());
log.info("singleton1:hasCode:{}",singleton1.hashCode());
}
}
/**
* 懒汉式,(静态代码块)
*/
class SingletonHungrySync {
private static SingletonHungryManSync instance;
private SingletonHungrySync() {
}
//提供一个静态的公有方法,同时加入同步处理代码synchronized, 解决线程安全问题
public static synchronized SingletonHungryManSync getInstance() {
if(null==instance){
instance=new SingletonHungryManSync();
}
return instance;
}
}
5、懒汉式(线程安全,同步代码块(线程不安全)
不推荐使用
java
@Slf4j
public class SingletonHungryManSyncCode {
public static void main(String[] args) {
SingletonHungrySyncCode singleton = SingletonHungrySyncCode.getInstance();
SingletonHungrySyncCode singleton1 = SingletonHungrySyncCode.getInstance();
log.info("比对结果:{}", singleton == singleton1);
log.info("singleton :hasCode:{}", singleton.hashCode());
log.info("singleton1:hasCode:{}", singleton1.hashCode());
}
}
class SingletonHungrySyncCode {
private static SingletonHungrySyncCode instance;
private SingletonHungrySyncCode() {
}
public static SingletonHungrySyncCode getInstance() {
if (null == instance) {
//进入if再加锁,创建多个实例,不安全(不推荐使用)
synchronized (SingletonHungrySyncCode.class) {
instance = new SingletonHungrySyncCode();
}
}
return instance;
}
}
6、双重检查
推荐使用
java
@Slf4j
public class SingletonDoubleCheckMain {
public static void main(String[] args) {
SingletonDoubleCheck singleton = SingletonDoubleCheck.getSingleton();
SingletonDoubleCheck singleton2 = SingletonDoubleCheck.getSingleton();
log.info("比对结果:{}", singleton == singleton2);
log.info("singleton :hashCode:{}", singleton.hashCode());
log.info("singleton2:hashCode:{}", singleton.hashCode());
}
}
class SingletonDoubleCheck {
private static volatile SingletonDoubleCheck singleton;
private SingletonDoubleCheck() {
}
/**
* 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
*/
public static synchronized SingletonDoubleCheck getSingleton() {
if (null == singleton) {
synchronized (SingletonDoubleCheck.class) {
if (null == singleton) {
singleton = new SingletonDoubleCheck();
}
}
}
return singleton;
}
}
7、静态内部类
推荐使用
java
@SuppressWarnings("All")
@Slf4j
public class SingletonStaticInnerMain {
public static void main(String[] args) {
SingletonStaticInner singleton = SingletonStaticInner.getInstance();
SingletonStaticInner singleton2 = SingletonStaticInner.getInstance();
log.info("静态内部类完成单例模式");
log.info("比对结果:{}", singleton == singleton2);
log.info("singleton :hashCode:{}", singleton.hashCode());
log.info("singleton2:hashCode:{}", singleton.hashCode());
}
}
class SingletonStaticInner {
private SingletonStaticInner() {
}
/**
* 写一个静态内部类,该类中有一个静态属性SingletonStaticInner
*/
private static class SingletonInstance {
private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
}
/**
* 提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE;
*/
public static SingletonStaticInner getInstance() {
return SingletonInstance.INSTANCE;
}
}
8、枚举
java
@Slf4j
public class SingletonEnumMain {
public static void main(String[] args) {
SingletonEnum singleton = SingletonEnum.INSTANCE;
SingletonEnum singleton2 = SingletonEnum.INSTANCE;
log.info("比对结果:{}", singleton == singleton2);
log.info("singleton :hashCode:{}", singleton.hashCode());
log.info("singleton2:hashCode:{}", singleton.hashCode());
}
}
enum SingletonEnum {
//属性
INSTANCE;
}
总结、以上推荐使用的是:
饿汉式,静态内部类,双重检查,枚举
单例使用注意事项:
1、单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要平凡创建校会的对象,使用单例模式可以提高系统性能
2、想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
3、单例模式适用的场景:需要频繁的进行创建和销毁对象,创建对象时消耗过多或者耗费资源过多(即:重量级对象),
但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)