简介
首先讲讲什么是单例模式,首先我们在程序设计过程中,会遇到这么一个问题。当我们设计好一个类之后,我们会发现我们可以在别的类中调用类的构造方法实例化一个对象。并且通过实例化对象调用类中的属性和方法。那么问题来了,如果存在某个类,这个类对于程序来说只需要产生一个类的时候,并且我们需要强制要求此类只能产生一个对象应该怎么办?这个时候我们就可以用到我们的单例设计模式。所谓单例设计就是构造方法私有化,在类中实例化对象,通过类的静态方法调用类中的属性和方法。其中单例设计又分为两种:1.饿汉式:在系统加载类的时候就会自动提供实例对象。2.懒汉式:在第一次使用的时候进行实例处理。
饿汉式
饿汉式单例设计模式就是在系统加载类的时候就会自动提供实例对象。通过这个概念我们就可以考虑一下,如何才能实现饿汉式单例设计。其实我们就可以将对象设置成一个静态的属性,再通过一个静态方法来获得这个属性。因为我们知道同一个类中静态属性只能静态访问。下面来看看具体例子。
public class Singleton {
private static final Singleton SINGLETON = new Singleton();
private Singleton() {
System.out.println("饿汉式单例设计构造方法");
}
public static Singleton getSingloten(){
return SINGLETON;
}
public void print(){
System.out.println("饿汉式单例设计");
}
}
上面就是一个单例设计的例子。在类中我们静态实例化了一个对象,并且有一个静态方法可以获得此对象。当我们需要用到此类时,直接通过类名就可以调用静态方法得到对象。
懒汉式
懒汉式单例设计在第一次使用的时候进行实例处理。和饿汉式设计的区别就在于懒汉式设计是在调用静态方法的时候才会产生实例化对象,而不是系统直接提供。下面来看看具体事例:
public class Singleton {
private static Singleton SINGLETON;
private Singleton() {
System.out.println("懒汉式单例设计构造方法");
}
public static Singleton getSingloten(){
if (SINGLETON == null){
SINGLETON = new Singleton();
}
return SINGLETON;
}
public void print(){
System.out.println("懒汉式单例设计");
}
}
通过这种单例设计我们就能达到只能得到一个对象的目的。但是这种懒汉式单例设计还是存在一个问题。是什么呢?来看看这个例子。
for (int i = 0; i < 3; i++) {
new Thread(()->{
Singleton.getSingloten().print();
}).start();
}
当我们使用多线程的时候调用静态方法获得对象的时候运行结果告诉我们仿佛并没有我们想象的那样只产生一个对象。而是产生了三个对象。运行结果如下图所示:
通过分析,我发现,当我们在多线程中访问静态方法时,线程是同时访问的,并且同时判断对象是否为空。三个线程同时得到对象为空的结果,所以产生了三个对象。那么怎么去解决呢?
我想我们可以通过线程的同步操作来实现这个操作。实现方法如下:
public static synchronized Singleton getSingloten(){
if (SINGLETON == null){
SINGLETON = new Singleton();
}
return SINGLETON;
}
同步操作就是当有一个线程在操作的时候,其他的线程就等待,这样就避免了线程同时获得对象为空的结果。但是这样加同步操作好像也不太合适,因为我们需要做的就只是同步操作判断对象是否为空的部分,所以将整个方法设为同步操作有点过于草率。因此我们还可以这样优化一下:
public static Singleton getSingloten(){
if (SINGLETON == null){
synchronized (Singleton.class) {
if (SINGLETON == null) {
SINGLETON = new Singleton();
}
}
}
return SINGLETON;
}
来看看运行结果:
构造方法确实是只被调用了一次,这样也达到了我们单例设计只产生一个对象的目的。有了这样的设计,我们的单例设计才算是完美。