保证在整个的软件系统中,对某个类只能存在一个对象实例
,并且该类只提供一个取得其对象实例的方法(静态方法)。对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
需要频繁的进行创建和销毁的对象
、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象
、工具类对象
、频繁访问数据库或文件的对象(比如数据源、session工厂等)
package com.atguigu.singleton.type1;
public class SingletonTest01 {
public static void main(String[] args) {
//测试
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
//饿汉式(静态变量)
class Singleton {
//1. 构造器私有化, 外部不能new
private Singleton() {
}
//2.本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
【运行结果】
true
instance.hashCode=1554874502
instance2.hashCode=1554874502
Process finished with exit code 0
【分析】
这种方式基于classloader机制避免了多线程的同步问题
,不过,instance在类装载时就实例化,在单例模式中大多数都是调用get lnstance
方法, 但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法) 导致类装载,这时候初始化instance就没有达到lazy loading的效果这种单例模式可用,可能造成内存浪费
package com.atguigu.singleton.type2;
public class SingletonTest02 {
public static void main(String[] args) {
//测试
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
//饿汉式(静态变量)
class Singleton {
//1. 构造器私有化, 外部能new
private Singleton() {
}
//2.本类内部创建对象实例
private static Singleton instance;
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
【分析】
package com.atguigu.singleton.type3;
public class SingletonTest03 {
public static void main(String[] args) {
System.out.println("懒汉式1 , 线程不安全~");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
//即懒汉式
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
【分析】
package com.atguigu.singleton.type4;
public class SingletonTest04 {
public static void main(String[] args) {
System.out.println("懒汉式2 , 线程安全~");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
// 懒汉式(线程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {
}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
//即懒汉式
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
添加synchronized
关键字,这样子当一个线程在执行这个方法的时候,其他线程不能执行这个方法
【分析】
class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
【分析】
package com.atguigu.singleton.type6;
public class SingletonTest06 {
public static void main(String[] args) {
System.out.println("双重检查");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
class Singleton {
//volatile:在Java中,volatile关键字可以保证变量的内存可见性。
//当一个变量被声明为volatile时,编译器和处理器会注意到这个变量可能会被其他线程并发地访问。
//这样可以避免线程之间的数据竞争,并确保多线程环境下变量的值是最新的。
private static volatile Singleton instance;
private Singleton() {
}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
//同时保证了效率, 推荐使用
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
保证只有一个线程创建实例
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
【分析】
package com.atguigu.singleton.type7;
public class SingletonTest07 {
public static void main(String[] args) {
System.out.println("使用静态内部类完成单例模式");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
// 静态内部类完成, 推荐使用
class Singleton {
//构造器私有化
private Singleton() {}
//写一个静态内部类,该类中有一个静态属性 Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
【分析】
避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
package com.atguigu.singleton.type8;
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
instance.sayOK();
}
}
//使用枚举,可以实现单例, 推荐
enum Singleton {
INSTANCE; //属性
public void sayOK() {
System.out.println("ok~");
}
}
【运行】
true
1554874502
1554874502
ok~
【分析】
【题目】
请编写Triple类,实现最多只能生成3个Triple类的实例,实例编号分别为0,1,2且可以通过getInstance(int id)来获取该编号对应的实例(题目来源于《图解设计模式》)
【代码实现】
public class Triple {
private static volatile Triple[] arr = new Triple[3];
private Triple() {
}
public static Triple getInstance(int index) {
if (index >= arr.length) {
throw new RuntimeException("索引超出,示例数量只有" + arr.length + "个");
}
if (arr[index] == null) {
synchronized (Triple.class) {
if (arr[index] == null) {
arr[index] = new Triple();
}
}
}
return arr[index];
}
}
public class TripleMain {
public static void main(String[] args) {
System.out.println("Start.");
for (int i = 0; i < 9; i++) {
Triple triple = Triple.getInstance(i % 3);
System.out.println(i + ":" + triple);
}
System.out.println("End.");
}
}
【运行】
Start.
0:com.atguigu.singleton.A2.Triple@5cad8086
1:com.atguigu.singleton.A2.Triple@6e0be858
2:com.atguigu.singleton.A2.Triple@61bbe9ba
3:com.atguigu.singleton.A2.Triple@5cad8086
4:com.atguigu.singleton.A2.Triple@6e0be858
5:com.atguigu.singleton.A2.Triple@61bbe9ba
6:com.atguigu.singleton.A2.Triple@5cad8086
7:com.atguigu.singleton.A2.Triple@6e0be858
8:com.atguigu.singleton.A2.Triple@61bbe9ba
End.
本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。