单例模式
单例模式分为四大类,饿汉式、懒汉式、静态内部类、枚举
饿汉式
优点:类装载时进行实例化,避免同步问题
缺点:造成内存浪费
实现一
1.构造器私有化
2.内部创建对象实例
3.提供静态方法
public class Type1 {
public static void main(String[] args) {
SingleTon1 instance = SingleTon1.getInstance();
SingleTon1 instance1 = SingleTon1.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon1{
// 加载实例化
private static final SingleTon1 instance = new SingleTon1();
private SingleTon1(){}
public static SingleTon1 getInstance(){
return instance;
}
}
实现二
1.构造器私有化
2.静态变量
3.静态代码块初始化
public class Type2 {
public static void main(String[] args) {
SingleTon2 instance = SingleTon2.getInstance();
SingleTon2 instance1 = SingleTon2.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon2{
private static SingleTon2 instance;
private SingleTon2(){}
// 静态块
static {
instance = new SingleTon2();
}
public static SingleTon2 getInstance(){
return instance;
}
}
懒汉式
方案一(线程不安全)
1.静态变量
2.构造函数私有化
3.静态方法调用时创建实例
public class Type3 {
public static void main(String[] args) {
SingleTon3 instance = SingleTon3.getInstance();
SingleTon3 instance1 = SingleTon3.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon3 {
private static SingleTon3 instance;
private SingleTon3() {
}
public static SingleTon3 getInstance() {
if (instance == null) {
instance = new SingleTon3();
}
return instance;
}
}
方案二(线程安全同步锁)
1.静态变量
2.构造函数私有化
3.静态方法调用时加synchronized同步锁,创建实例
缺点:效率低
public class Type4 {
public static void main(String[] args) {
SingleTon4 instance = SingleTon4.getInstance();
SingleTon4 instance1 = SingleTon4.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon4 {
private static SingleTon4 instance;
private SingleTon4() {
}
// 同步锁,所有线程阻塞排队
public static synchronized SingleTon4 getInstance() {
if (instance == null) {
instance = new SingleTon4();
}
return instance;
}
}
方案三(同步代码块,线程不安全, 不能用、不能用、不能用)
public class Type5 {
public static void main(String[] args) {
SingleTon5 instance = SingleTon5.getInstance();
SingleTon5 instance1 = SingleTon5.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon5 {
private static SingleTon5 instance;
private SingleTon5() {
}
public static SingleTon5 getInstance() {
if (instance == null) {
// 同步代码块,但是有两个线程同时进入if判断,就会创建多个实例
synchronized (Type5.class){
instance = new SingleTon5();
}
}
return instance;
}
}
方案四(双重检查)
优点:线程安全、懒加载、效率高
public class Type6 {
public static void main(String[] args) {
SingleTon6 instance = SingleTon6.getInstance();
SingleTon6 instance1 = SingleTon6.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon6 {
private volatile static SingleTon6 instance;
private SingleTon6() {
}
public static SingleTon6 getInstance() {
if (instance == null) {
synchronized (Type5.class){
if(instance == null){
instance = new SingleTon6();
}
}
}
return instance;
}
}
静态内部类
静态内部类特点,外部类装载时,内部类不会被装载
调用静态方法时,装载静态内部类,线程安全
静态内部类中定义静态变量
优点:静态内部类实现了延迟加载,线程安全有jvm控制
public class Type7 {
public static void main(String[] args) {
SingleTon7 instance = SingleTon7.getInstance();
SingleTon7 instance1 = SingleTon7.getInstance();
System.out.println(instance == instance1);
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}
class SingleTon7 {
private SingleTon7() {
}
private static class SingleTon7Holder {
private static final SingleTon7 INSTANCE = new SingleTon7();
}
public static SingleTon7 getInstance() {
return SingleTon7Holder.INSTANCE;
}
}
枚举
避免线程不安全,防止反序列化重新创建新对象
public class Type8 {
public static void main(String[] args) {
SingleTonEnum.INSTANCE.whateverMethod();
}
}
enum SingleTonEnum {
INSTANCE;
public void whateverMethod() {
System.out.println("hhh");
}
}
举例
JDK 中 RunTime
总结
1.频繁创建或销毁的对象适合使用单例模式
2.创建对象耗时过长或者资源过多适合使用单例模式
3.频繁用到的对象,类似工具类等,适合使用单例模式