• java设计模式单例模式


     创建型模式: – 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。

    • 结构型模式: – 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模 式。

    • 行为型模式: – 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模 式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

    单例模式:

    • 核心作用: – 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

    • 常见应用场景:

    – Windows的Task Manager(任务管理器)就是很典型的单例模式 – windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

    – 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。

    – 网站的计数器,一般也是采用单例模式实现,否则难以同步。

    – 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作 ,否则内容不好追加。

    – 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。

    – 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。

    – Application 也是单例的典型应用

    – 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理 – 在servlet编程中,每个Servlet也是单例 – 在spring MVC框架/struts1框架中,控制器对象也是单例

    单例模式的优点:

    – 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动 时直接产生一个单例对象,然后永久驻留内存的方式来解决 – 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计 一个单例类,负责所有数据表的映射处理

     常见的五种单例模式实现方式:

    – 主要: • 饿汉式(线程安全,调用效率高。 但是,不能延时加载。)

    • 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)

    – 其他: • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)

    • 静态内部类式(线程安全,调用效率高。 但是,可以延时加载)

    • 枚举单例(线程安全,调用效率高,不能延时加载)

    饿汉式实现(单例对象立即加载)

    //饿汉式单例
    public class Singleton01 {
    	//类初始化时,立即加载这个对象
    	//加载类是天然的线程安全的,(没有延时加载的优势)
       private static Singleton01 instance=new Singleton01();
       private Singleton01(){
    	   
       }
       //方法没有同步,调用效率高
       public static Singleton01 getInstance(){
    	   return instance;
       } 
    }
    

      懒汉式

    //懒汉式
    public class Singleton02 {
    	//类初始化时,不初始化这个对象(真正用到的时候在创建)
        private static Singleton02 instance;
        private Singleton02(){  //私有构造器
        	
        }
        //方法同步,调用效率低
        public static synchronized Singleton02 getInstance(){
        	if(instance==null){
        		instance=new Singleton02();
        	}
        	return instance;
        }
    }
    

      双重检索:

    //双重检测所机制
    //由于编译器优化原因和jvm底层内部模型原因,有时候回出现问题
    public class Singleton03 {
    	private static Singleton03 instance=null;
    	
    	public static Singleton03 getInstance(){
    		if(instance==null){
    			Singleton03 sc;
    			synchronized (Singleton03.class){
    				sc=instance;
    				if(sc==null){
    					synchronized(Singleton03.class){
    						if(sc==null){
    							sc=new Singleton03();
    						}
    					}
    					instance=sc;
    				}
    			}
    		}
    		return instance;
    	}
    	private Singleton03(){
    		
    	}
    }
    

      静态内部类:

    //静态内部类
    public class Singleton04 {
    	 //要点:
    	//– 外部类没有static属性,则不会像饿汉式那样立即加载对象。
    	//– 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的。 
    	//instance是static final 类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,
    	//从而保证了线程安全性. – 兼备了并发高效调用和延迟加载的优势!
    
    	private static class Singleton04ClassInstance {
    		private static final Singleton04 instance = new Singleton04();
    	}
    	private Singleton04() {
    
    	}
    	public static  Singleton04 getInstance() {
    		return Singleton04ClassInstance.instance;
    	}	
    }
    

      枚举模式:

    //枚举单例(没有延时加载)
    public enum Singleton05 {
        //定义一个枚举,枚举 元素本身就是一个单例
    	INSTANCE;
    	//添加自己需要的元素
    	public void singletonOperation(){
    		
    	}
    }
    

      

    public static void main(String[] args) {
    		Singleton01 s1=Singleton01.getInstance();
    		Singleton01 s2=Singleton01.getInstance();
    		System.out.println(s1);
    		System.out.println(s2);
    	}
    

      

     常见的五种单例模式实现方式

    – 主要: • 饿汉式(线程安全,调用效率高。 但是,不能延时加载。) • 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)

    – 其他: • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用) • 静态内部类式(线程安全,调用效率高。 但是,可以延时加载) • 枚举式(线程安全,调用效率高,不能延时加载。并且可以天然的防止反射和反序列 化漏洞!) • 如何选用? – 单例对象  占用  资源 少,不需要  延时加载: • 枚举式   好于   饿汉式 – 单例对象  占用  资源 大,需要 延时加载: • 静态内部类式   好于  懒汉式

     反射和序列化破坏单例:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    
    public class SingletonTest01 {
    	public static void main(String[] args) throws Exception{
    		Singleton06 s1=Singleton06.getInstance();
    		Singleton06 s2=Singleton06.getInstance();
    		
    		System.out.println(s1);
    	    System.out.println(s2);
    	    
    	    //通过反射的方式直接调用私有构造器
    		Class<Singleton06> clazz= (Class<Singleton06>)Class.forName("demo.singleton.Singleton06");
    		//获取无参数构造器
    		Constructor<Singleton06> c=clazz.getDeclaredConstructor(null);
    		//跳过权限的检查
    		c.setAccessible(true);
    		Singleton06 s3=c.newInstance();
    		Singleton06 s4=c.newInstance();
    		
    		System.out.println(s3);
    		System.out.println(s4);
    		
    		//通过序列化的方式构造多个对象
    		FileOutputStream fos=new FileOutputStream("d:/a.txt");
    		ObjectOutputStream oos=new ObjectOutputStream(fos);
    		oos.writeObject(s1);
    		oos.close();
    		fos.close();
    		
    		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/a.txt"));
    		Singleton06 s5=(Singleton06) ois.readObject(); 
    		System.out.println(s5);
    	}
    }
    

      

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    
    public class SingletonTest01 {
    	public static void main(String[] args) throws Exception{
    		Singleton06 s1=Singleton06.getInstance();
    		Singleton06 s2=Singleton06.getInstance();
    		
    		System.out.println(s1);
    	    System.out.println(s2);
    	    
    	    //通过反射的方式直接调用私有构造器
    		Class<Singleton06> clazz= (Class<Singleton06>)Class.forName("demo.singleton.Singleton06");
    		//获取无参数构造器
    		Constructor<Singleton06> c=clazz.getDeclaredConstructor(null);
    		//跳过权限的检查
    		c.setAccessible(true);
    		Singleton06 s3=c.newInstance();
    		Singleton06 s4=c.newInstance();
    		
    		System.out.println(s3);
    		System.out.println(s4);
    		
    		//通过序列化的方式构造多个对象
    		FileOutputStream fos=new FileOutputStream("d:/a.txt");
    		ObjectOutputStream oos=new ObjectOutputStream(fos);
    		oos.writeObject(s1);
    		oos.close();
    		fos.close();
    		
    		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/a.txt"));
    		Singleton06 s5=(Singleton06) ois.readObject(); 
    		System.out.println(s5);
    	}
    }
    

      测试:

    import java.util.concurrent.CountDownLatch;
    
    public class SingletonTest03 {
    	public static void main(String[] args) throws Exception {
    		long start=System.currentTimeMillis();
    		int threanNum=10;
    		final CountDownLatch countDownLath=new CountDownLatch(threanNum);
    				
    		
    		for(int i=0;i<10;i++){
    			new Thread(new Runnable(){
    				@Override
    				public void run(){
    					for(int i=0;i<1000000;i++){
    						//Object o=Singleton04.getInstance();
    						Object o=Singleton05.INSTANCE;
    					}
    					countDownLath.countDown();
    				}
    			}).start();
    		}
    		countDownLath.await();//mian线程阻塞,知道计数器变成0,才会继续往下执行
    		long end=System.currentTimeMillis();
    		System.out.println("总耗时:"+(end-start));
    	}
    }
    

      多线程情况的下的单例模式:

    //标准的单例模式
    public class SingletonDemo {
        private static volatile SingletonDemo instance=null;
        private SingletonDemo(){
            System.out.println(Thread.currentThread().getName()+
                    "	 我是构造方法SingletonDemo()");
        }
        //双端检索机制
        public static  SingletonDemo getInstance(){
            if(instance==null){
                synchronized (SingletonDemo.class){
                    if(instance==null)
                        instance=new SingletonDemo();
                }
            }
            return instance;
        }
    
        public static void main(String[] args) {
            for(int i=0;i<10;i++){
                new Thread(()->{
                 SingletonDemo.getInstance();
                },String.valueOf(i)).start();
            }
        }
    }
    

      

  • 相关阅读:
    linux环境weblogic开启远程调试
    C#相关资料
    pyqt5,pyside2学习过程中问题与疑惑记录--先记下问题,然后逐个解决
    任务记录-2020.10.1
    猜想:假如时间的快慢与物体的质量有关系。那长大之后,感觉时间过得越来越快,是不是大脑或者身体中某一个器官越长越大,然后导致时间越过越快。。。
    学习思路--学习一个新的东西,从哪些方面着手
    java bug记录
    记录要做的事情,把sql字符串替换写成工具网页。
    使用java代码本地测试远程rpc接口
    任务记录
  • 原文地址:https://www.cnblogs.com/sunliyuan/p/11838673.html
Copyright © 2020-2023  润新知