对某个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的方法(静态方法)
单例模式的八种方式:
1.饿汉式(静态变量)
2.饿汉式(静态代码块)
3.懒汉式(线程不安全)
4.懒汉式(线程安全,同步方法)
5.懒汉式(线程安全,同步代码块)
6.双重检查
7.静态内部类
8.枚举
饿汉式(静态变量)
public class Singleton1 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
//饿汉式(静态常量)
class Singleton{
//1.构造器私有化,外部不能new
private Singleton(){
}
//2.本类内部创建对象实例
private final static Singleton instance=new Singleton();
//3.提供一个公有的静态方法,返回实例对象
public static Singleton getInstance(){
return instance;
}
}
优缺点:
1.优点:写法简单,在类装载的时候就完成实例化。避免了线程同步问题
2.缺点:没有达到Lazy Loading(懒加载)的效果:如果从始到终没有用到这个实例就会产生内存浪费。
3.这种方式基于类加载机制避免了多线程的同步问题,但instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类加载的原因有很多,可能不是使用getInstance却导致类加载,导致没有实现懒加载,造成内存浪费
饿汉式(静态代码块)
public class Singleton2 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
//饿汉式(静态代码)
class Singleton{
//1.构造器私有化,外部不能new
private Singleton(){
}
//2.本类静态变量
private static Singleton instance;
//3.在静态代码块中创建单例对象
static{
instance=new Singleton();
}
//4.提供一个公有的静态方法,返回实例对象
public static Singleton getInstance(){
return instance;
}
}
优缺点:
1.优缺点跟饿汉式(静态常量)一样
懒汉式(线程不安全)
public class Singleton3 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
//懒汉式(线程不安全)
class Singleton{
//1.构造器私有化,外部不能new
private Singleton(){
}
private static Singleton instance;
//提供一个静态的公有方法,当使用到该方法时,才去创建instance对象
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
优缺点:
1.实现懒加载,但只能在单线程的时候使用。
2.线程不安全的原因:再多线程下,一个线程进入到if(instance==null)
判断语句块,还未执行下去,其他线程也通过了这个判断语句,这时便会产生多实例。
懒汉式(线程安全,同步方法)
public class Singleton4 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
//懒汉式(线程安全,同步方法)
class Singleton{
private Singleton(){
}
private static Singleton instance;
//提供一个静态的公有方法,当使用到该方法时,才去创建instance对象
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
优缺点:
1.解决了线程不安全的问题
2.效率太低了,每个类想要获取实例都需要执行getInstance()同步,而其实这方法只需要一次实例化,其他方法直接return就可以。方法同步效率太低
懒汉式(线程安全,同步代码块)
垃圾,不用学
双重检查
public class Singleton6 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
class Singleton{
private Singleton(){
}
private static volatile Singleton instance;//volatile:修改值立即更新到主存
//加入双重检查,解决线程安全问题,同时解决懒加载问题
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
} }
}
优缺点:
1.Double-Check概念再多线程中常用,进行两次if(instance==null)
检查,保证线程安全。
2.实例化代码只执行一次,避免反复进行方法同步。
3.线程安全、懒加载;效率较高。
静态内部类
public class Singleton7 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.getInstance();
Singleton instance2=Singleton.getInstance();
System.out.println(instance1==instance2);//true
}
}
//静态内部类
//静态内部类特点:1.外部类装置的时候,内部静态类不会被装载 2.内部调用的时候,静态内部类只会执行一次
class Singleton{
private Singleton(){
}
//静态内部类,该类中有一个静态属性Singleton
//JVM处理类加载的时候是线程安全的
public static class SingletonInstance{
private static final Singleton instance=new Singleton();
}
//提供一个静态公有方法,直接返回SingletonInstance.instance
public static Singleton getInstance(){
return SingletonInstance.instance;
}
}
优缺点:
1.采用类加载机制来保证初始化实例的时候只有一个线程。
2.静态内部方法在Singleton类被装载时,不会立即实例化,调用getInstance时才会实例化。
3.类的静态属性只会在第一次加载的时候进行初始化。
4.线程安全、懒加载、效率高。
枚举
public class Singleton8 {
public static void main(String[] args) {
//测试
Singleton instance1=Singleton.INSTANCE;
Singleton instance2=Singleton.INSTANCE;
System.out.println(instance1==instance2);//true
}
}
//枚举
enum Singleton{
INSTANCE;
public void sayOK(){
System.out.println("ok");
}
}
优缺点:
1.借助JDK1.5中添加的枚举类实现单例模式,不仅能避免多线程同步问题,而且还能防止反序列化重新创建对象。
2.Java作者推荐方式。
本文为本人的尚硅谷教程的笔记
视频地址:https://www.bilibili.com/video/av57936239
来源:CSDN
作者:是我弄得嘛
链接:https://blog.csdn.net/qq_38425719/article/details/103804488