此些是本人近期学习到的一些关于单例模式的知识,与各位分享学习
希望对各位能有所帮助,觉得有用记得点赞关注哟😁😁😁。
单例模式(七种创建方式)
饿汉式两种(静态斜体样式变量,静态块) 2
懒汉式两种(一次判空new,一次判空后new_+synchronized) 2
双重检查(两次判空第二判空加上synchronized同步) 1
静态内部类 1
枚举 1
饿汉式(两种实现方式,不会懒加载,线程安全,存在内存的浪费问题)
a. 静态常量:
私有化构造方法,创建一个静态的常量的对象实例,再创建一个公共的方法返回实例。
package singleton;
/**
* 饿汉式单例模式(静态常量)
* 存在内存的浪费的问题
* 即对象在实例化后我们开发的过程中却没有用到该对象
* 所以此时造成了内存的浪费
* @author 29226
*
*/
public class SingeltonTests01 {
public static void main(String[] args) {
/**
* 此方式保证了每次创建的对象都是同一个
* 也就是只有一个对象实例
* 输出的结果为true 和相同hashcode
* 即 s 和s1是相等的是同一个对象实例
*/
Single s=Single.getInstance();
Single s1=Single.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single{
//第一步私有化构造方法
private Single() {
}
//第二步定义静态的私有的对象实例
private static Single instance=new Single();
//第三步提供一个公共静态的方法返回对象实例
public static Single getInstance() {
return instance;
}
}
b.静态代码块:私有化构造方法 ,再一个静态块中创建一个静态的常量的对象实例,再创建一个公共的方法返回实例
package singleton;
/**
* 饿汉式单例模式(静态块)
*
* @author 29226
*
*/
public class SingeltonTests02 {
public static void main(String[] args) {
/**
* 此方式保证了每次创建的对象都是同一个
* 也就是只有一个对象实例
* 输出的结果为true 和相同hashcode
* 即 s 和s1是相等的是同一个对象实例
*/
Single2 s=Single2.getInstance();
Single2 s1=Single2.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single2 {
//第一步私有化构造方法
private Single2() {
}
//第二步定义静态的私有的对象实例
private static Single2 instance;
//第三步在静态代码块中实例化对象
static {
instance=new Single2();
}
//第四步提供一个公共静态的方法返回对象实例
public static Single2 getInstance() {
return instance;
}
}
懒汉式(3种) 实现方式1: 私有化构造函数,申明一个静态的私有的对象(要实现单例的那个对象),
创建一个公共的方法返回对象实例,在返回的之前要进行判断时候对象为null,对象为空的时候就new,不是空就直接返回。
package singleton;
/**
* 懒汉式 写法 1(线程不安全)
* 此方式不会造成内存的浪费
* 当一个线程进入if条件判断的时候此时instance为空
* 线程 1创建 实例
* 但在线程1new 还没有结束的时候 线程2也来到了此时if判断instance任然为空
* 此时线程2也开始 new intance
* 这样就违背了单例模式
*
* @author 29226
*
*/
public class SingeltonTest03_layz {
public static void main(String[] args) {
System.out.println("懒汉式方式1 线程不安全!");
Single3 s=Single3.getInstance();
Single3 s1=Single3.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single3{
//私有化构造方法
private Single3() {
}
//定义静态对象
private static Single3 instance;
//提供一个静态的公共的方法
public static Single3 getInstance() {
if(instance==null) {
instance=new Single3();
}
return instance;
}
}
实现方式2(解决了线程的同步问题):
私有化构造函数,申明一个静态的私有的对象(要实现单例的那个对象),创建一个公共的方法返回对象实例,在这方法前加synchronized修饰,基解决线程安全问题,在返回的之前要进行判断时候对象为null,对象为空的时候就new,不是空就直接返回。
package singleton;
/**
* 懒汉式 写法 2(线程安全)
* 此方式不会造成内存的浪费
* 但是效率低下
* 因为加了synchronized就使得每次调用getInstance方法的时候都会进行同步
* 而同步问题只会出现在第一创建实例的时候,所以当第一次创建完实例后其实就不用再同步
*所以导致了效率比较低下
*
*开发的时候不推荐使用此方式
*
*
* @author 29226
*
*/
public class SingeltonTest04_layz2 {
public static void main(String[] args) {
System.out.println("懒汉式方式2 线程安全!");
Single4 s=Single4.getInstance();
Single4 s1=Single4.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single4{
//私有化构造方法
private Single4() {
}
//定义静态对象
private static Single4 instance;
//提供一个静态的公共的方法加入synchronized 解决线程安全问题
public static synchronized Single4 getInstance() {
if(instance==null) {
instance=new Single4();
}
return instance;
}
}
双重检查 私有化构造函数,申明一个静态的私有的对象加上volatile修饰(要实现单例的那个对象
instance),创建一个公共的方法返回对象实例,在返回的之前要进行判断时候对象为null,对象为空的时候就进入同步方法中对instance再判断instance是否为null,如果是null则直接new
instance对象然后返回 ,不是空则跳出判断返回instance。
package singleton;
/**
* 双重检查 方式 (线程安全,效率也比较高)
* 此方式不会造成内存的浪费
* 推荐使用
*
* @author 29226
*
*/
public class SingeltonTest05_doubleCheck1 {
public static void main(String[] args) {
System.out.println("双重检查! 实现单例~");
Single5 s=Single5.getInstance();
Single5 s1=Single5.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single5{
//私有化构造方法
private Single5() {
}
/**
* 定义静态对象加volatile 关键字修饰保证每次都将intance 更新到主存中
*/
private static volatile Single5 instance;
//提供一个静态的公共的方法
public static Single5 getInstance() {
if(instance==null) {
//加入同步代码块和双重检查解决线程安全的问题和懒加载
synchronized(Single5.class){
if(instance==null) {
instance=new Single5();
}
}
}
return instance;
}
}
静态内部类
私有化构造函数,创建一个静态的内部类Instance然后在类的内部定义个私有的静态的常量对像实例属性,然后再外部类中定义一个公共的方法调用这内部类的私有静态常量对象并返回。
package singleton;
/**
*静态内部类 (线程安全,效率也比较高)
* 此方式不会造成内存的浪费
* 推荐使用
*
*此方式是利用JVM类加载时候是同步的从而实现的同步控制
*利用了当前类的加载不会导致静态内部类的加载从而实现懒加载
* @author 29226
*
*/
public class SingeltonTest06_staticInner {
public static void main(String[] args) {
System.out.println("静态内部类! 实现单例~");
Single6 s=Single6.getInstance();
Single6 s1=Single6.getInstance();
System.out.println(s==s1);
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
}
}
class Single6{
//私有化构造方法
private Single6() {
}
//定义静态的内部类
private static class Instance {
//定义静态常量对象实例
private static final Single6 instance =new Single6();
}
//提供一个静态的公共的方法
public static Single6 getInstance() {
return Instance.instance;
}
}
枚举方式实现
package singleton;
/**
* 枚举实现单例模式 (线程安全,效率高,同时也能实现反序列化)
* 推荐使用
* @author 29226
*
*/
public class SingletonTest07_enumerate {
public static void main(String[] args) {
Single7 i=Single7.INSTANCE;
Single7 i2=Single7.INSTANCE;
i.sayOk();
System.out.println(i==i2);
System.out.println(i.hashCode());
System.out.println(i2.hashCode());
}
/**
* 定义一个枚举类型
* @author 29226
*
*/
enum Single7{
INSTANCE;//属性
public void sayOk() {
System.out.println("ok!");
}
}
}