本文主要讲解设计模式的创建模式中的单例模式的饿汉式,它是在类加载时创建对象,它的实现方式有两种,一种是通过静态变量来实现,另一种是通过静态代码块来实现;以及饿汉式的两种实现方式,一种是线程不安全实现方式,另一种是通过通过synchronized
关键字实现的线程安全方式
单例类:
只能创建一个实例的类访问类:
使用单例类。饿汉式
:类加载就会导致改单实例对象被创建。
package pattern.singleton.hungrystyle.staticcode;
/**
* 饿汉式:静态成员变量
*/
public class Singleton {
//1.私有构造方法的创建-> 使得外部无法创建多个该类对象
private Singleton(){
}
//2.在本类中创建本类的对象-> 确保全局只有一个实例
private static Singleton singleton = new Singleton();
//3.提供一个公共的访问方式,让外界获取该对象
public static Singleton getSingleton(){
return singleton;
}
}
package pattern.singleton.hungrystyle.staticcode;
public class Test {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getSingleton();
Singleton singleton2 = Singleton.getSingleton();
//判断两次获取的Singleton对象是否是同一个对象
System.out.println(singleton1 == singleton2);
}
}
package pattern.singleton.hungrystyle.staticmethod;
/**
* 饿汉式:静态代码块
*/
public class Singleton {
//私有构造方法
private Singleton (){
}
//声明Singleton类型的变量
private static Singleton singleton;
//在静态代码块中将对象赋值给刚刚的变量
static{
singleton = new Singleton();
//因为这里的是静态代码块,静态只能访问静态,
// 所以上面的变量也必须是静态的。
}
//对外提供获取该类对象的方法
public static Singleton getSingleton(){
return singleton;
}
}
package pattern.singleton.hungrystyle.staticmethod;
public class Test {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getSingleton();
Singleton singleton2 = Singleton.getSingleton();
//判断两次获取到的Singleton对象是否是同一个
System.out.println(singleton1 == singleton2);
}
}
懒汉式
:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建。
对于这种每次调用getSingleton方法时都会重新创建一个对象,这会使得我们在测试类中判断我们通过Singleton类调用这个方法创建的对象的内存地址返回的结果会是false,因为每次都会创建一个新对象。我们可以添加if-else
来判断对象是否被创建,如果创建了就返回,没有就创建,使它只创建一次对象,从而满足我们的单例模式。
package pattern.singleton.lazystyle.Threadunsafe;
public class Singleton {
//1.私有方法的构造
private Singleton(){
}
//2.声明Singleton类型的变量 singleton
private static Singleton singleton;
//3.对外提供访问方式
public static Singleton getSingleton(){
//判断singleton是否为nuLL,如果为nuLL,说明还没有创建SingLeton类的对象
//如果没有,创建一个并返回,如果有,直接返回
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
package pattern.singleton.lazystyle.Threadunsafe;
public class Test {
public static void main(String[] args) {
Singleton mysingleton1 = Singleton.getSingleton();
Singleton mysingleton2 = Singleton.getSingleton();
System.out.println(mysingleton1 == mysingleton2);
}
}
CPU
的执行权,也会进入到判断里面。但是会出现线程安全问题。package pattern.singleton.lazystyle.Threadsafe;
public class Singleton {
//1.私有方法的构造
private Singleton(){
}
//2.声明Singleton类型的变量 singleton
private static Singleton singleton;
//3.对外提供访问方式
public static synchronized Singleton getSingleton(){
//判断singleton是否为nuLL,如果为nuLL,说明还没有创建SingLeton类的对象
//如果没有,创建一个并返回,如果有,直接返回
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
package pattern.singleton.lazystyle.Threadsafe;
public class Test {
public static void main(String[] args) {
Singleton mysingleton3 = Singleton.getSingleton();
Singleton mysingleton4 = Singleton.getSingleton();
System.out.println(mysingleton3 == mysingleton4);
}
}
synchronized
关键字的时候,就变成了线程安全式的单例模式,线程2就没法进来获取cpu的执行权,因为它是同步锁,只有等线程1完成了才能执行线程2。synchronized
实现懒加载的效果的同时,又解决了线程安全问题。但是在getSingleton()方法上添加了synchronized
关键字,会导致该方法的执行效果非常低。从上面的代码我们可以看出,出现线程安全问题是在初始化singleton
的时候,一旦初始化完成就不存在了。