目录
1、单例类只能有一个实例
2、单例类必须自己创建自己唯一的实例
3、单例类必须给其他对象提供这一实例
简而言之,可以看出单例模式就是一个实例,然后提供给整个系统,而不是像new一样,创建一个,用一个,每一个都是不一样的;
举个例子:之前我们学的Redis就是用了单例模式,他的对象常被涉及成单例,因为缓存才用的是单线程:也就是一个个来,避免一个端口被多个请求同时调用。总之,单例模式就是为了避免不一样的状态;
我们知道,通常我们会通过new关键字来创建一个新的对象。这个时候类的构造函数是public公有的,你可以随意创建多个类的实例。所以,1.首先我们需要把构造函数改为private私有的,这样就不能随意new对象了,也就控制了多个实例的随意创建。
然后,2.定义一个私有的静态属性,来代表类的实例,它只能类内部访问,不允许外部直接访问。
最后,3.通过一个静态的公有方法,把这个私有静态属性返回出去,这就为系统创建了一个全局唯一的访问点。
package 单例模式;
/**
* @author diao 2022/3/10
*/
public class Singleton {
private Singleton(){
}
private static Singleton singleton=null;
//静态工厂方法
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
这里有两个关键点:
1、Singletion类的构造方法是私有的——>那么就避免了类在外部被实例化(new xxx这种),在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问;
当然,反射可以访问私有化的构造方法;
2、getInstance()方法,如果实例为空,就实例化一次;
package 单例模式;
/**
* @author diao 2022/3/10
*/
//饿汉式单例
public class Singleton1 {
private Singleton1(){
}
//final直接让类初始化时候:自行实例化
private static final Singleton1 single=new Singleton1();
public static Singleton1 getInstance(){
return single;
}
}
特点:
这里关键在于final,意思就是在类创建的时候就已经创建类的对象,以后不再改变了;
所以这里是线程安全的,因为不能改变了;
饿汉:类一旦加载,就把单例初始化了,在那个getInstance方法之前,单例就已经存在;
懒汉:在调用getInstance时才会实例化这个单例;
从线程安全来看:
饿汉式线程安全;
懒汉本身是线程非安全的;
从资源占用与性能来看:
饿汉式因为类加载就实例化对象了,所以就算你以后不用它,都会占用一定内存;
懒汉式的话,会延迟加载,需要的时候才实例化,所以说内存占用较少,但是性能肯定没饿汉式快;
联想联系:
饿汉式有点像Spring框架中的ApplicationContext,一开始,全部给你加载了;
懒汉式有点像BeanFactory,只有需要bean的时候,才会去加载你需要的,就跟懒加载一样;
比如说你的代码被多个线程运行,而这些线程同时运行这断代码时,运行结果如果与单线程运行的结果一样,说明就是线程安全的;
可能有点抽象;
或者说,如果一类所提供的接口或者说代码中的操作对于线程来说是原子操作——>原子性,执行就执行完,不然就不执行;那么线程就是安全的,不需要考虑像synchronized这样的同步代码块;
package 单例模式;
/**
* @author diao 2022/3/10
*/
public class TestSingletion {
public String name=null;
private TestSingletion(){
}
//用volatile声明一个TestSingletion类型的引用指向null
private static volatile TestSingletion instance=null;
public static TestSingletion getInstance(){
if(instance==null){
synchronized (TestSingletion.class){
if (instance==null){
instance=new TestSingletion();
}
}
}
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void print(){
System.out.println("this is name"+name);
}
}
package 单例模式;
/**
* @author diao 2022/3/10
*/
public class Test_Main {
public static void main(String[] args) {
TestSingletion instance = TestSingletion.getInstance();
TestSingletion instance1 = TestSingletion.getInstance();
instance.setName("Mike");
instance1.setName("Fairy");
instance.print();
instance1.print();
//判断是否是同一个实例
if(instance==instance1){
System.out.println("创建的是同一个实例");
}else{
System.out.println("创建的不是同一个实例");
}
}
}
这里还涉及了volatile的理解,这里还没弄懂,先记录到这;