-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
12 lines (12 loc) · 6.89 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[Java 单例模式]]></title>
<url>%2Fw77w%2F2019%2F04%2F08%2FJava%20%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%2F</url>
<content type="text"><![CDATA[单例(Singleton)模式 也叫单态模式概述:单例(Singleton)模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任。 从另一个角度来说,Singleton模式其实也是一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责! 核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 应该在什么时候下使用单例模式? 举一个小例子,在我们的windows桌面上,我们打开了一个回收站,当我们试图再次打开一个新的回收站时,Windows系统并不会为你弹出一个新的回收站窗口。,也就是说在整个系统运行的过程中,系统只维护一个回收站的实例。这就是一个典型的单例模式运用。 继续说回收站,我们在实际使用中并不存在需要同时打开两个回收站窗口的必要性。假如我每次创建回收站时都需要消耗大量的资源,而每个回收站之间资源是共享的,那么在没有必要多次重复创建该实例的情况下,创建了多个实例,这样做就会给系统造成不必要的负担,造成资源浪费。 再举一个例子,网站的计数器,一般也是采用单例模式实现,如果你存在多个计数器,每一个用户的访问都刷新计数器的值,这样的话你的实计数的值是难以同步的。但是如果采用单例模式实现就不会存在这样的问题,而且还可以避免线程安全问题。同样多线程的线程池的设计一般也是采用单例模式,这是由于线程池需要方便对池中的线程进行控制 同样,对于一些应用程序的日志应用,或者web开发中读取配置文件都适合使用单例模式,如HttpApplication 就是单例的典型应用。 从上述的例子中我们可以总结出适合使用单例模式的场景和优缺点: 适用场景 需要生成唯一序列的环境 需要频繁实例化然后销毁的对象。 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。 方便资源相互通信的环境 优点 实现了对唯一实例访问的可控 对于一些需要频繁创建和销毁的对象来说可以提高系统的性能。 缺点 不适用于变化频繁的对象 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出。 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失。 一:只适合单线程环境(不好)1234567891011121314151617package test;/** * @author Phoenix * */public class Singleton { private static Singleton instance=null; private Singleton(){ } public static Singleton getInstance(){ if(instance == null){ instance=new Singleton(); } return instance; }} 注解: Singleton的静态属性instance中,只有instance为null的时候才创建一个实例,构造函数私有,确保每 次都只创建一个,避免重复创建。 缺点:只在单线程的情况下正常运行,在多线程的情况下,就会出问题。例如:当两个线程同时运行到判断 instance是否为空的if语句,并且instance确实没有创建好时,那么两个线程都会创建一个实例。 二:多线程的情况可以用。(懒汉式,不好)123456789101112public class Singleton { private static Singleton instance=null; private Singleton(){ } public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; }} 注解:在解法一的基础上加上了同步锁,使得在多线程的情况下可以用。例如:当两个线程同时想创建实例, 由于在一个时刻只有一个线程能得到同步锁,当第一个线程加上锁以后,第二个线程只能等待。第一个 线程发现实例没有创建,创建之。第一个线程释放同步锁,第二个线程才可以加上同步锁,执行下面的 代码。由于第一个线程已经创建了实例,所以第二个线程不需要创建实例。保证在多线程的环境下也只 有一个实例。 缺点:每次通过getInstance方法得到singleton实例的时候都有一个试图去获取同步锁的过程。而众所周知, 加锁是很耗时的。能避免则避免。 三:加同步锁时,前后两次判断实例是否存在(可行)12345678910111213141516public class Singleton { private static Singleton instance=null; private Singleton(){ } public static Singleton getInstance(){ if(instance==null){ synchronized(Singleton.class){ if(instance==null){ instance=new Singleton(); } } } return instance; }} 注解:只有当instance为null时,需要获取同步锁,创建一次实例。当实例被创建,则无需试图加锁。 缺点:用双重if判断,复杂,容易出错。 四:饿汉式(建议使用)123456789public class Singleton { private static Singleton instance=new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return instance; }} 注解:初试化静态的instance创建一次。如果我们在Singleton类里面写一个静态的方法不需要创建实例,它 仍然会早早的创建一次实例。而降低内存的使用率。 缺点:没有lazy loading的效果,从而降低内存的使用率。 五:静态内部内。(建议使用)1234567891011public class Singleton { private Singleton(){ } private static class SingletonHolder{ private final static Singleton instance=new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.instance; }} 注解:定义一个私有的内部类,在第一次用这个嵌套类时,会创建一个实例。而类型为SingletonHolder的 类,只有在Singleton.getInstance()中调用,由于私有的属性,他人无法使用SingleHolder,不调用 Singleton.getInstance()就不会创建实例。 优点:达到了lazy loading的效果,即按需创建实例。]]></content>
<tags>
<tag>java</tag>
<tag>java设计模式</tag>
</tags>
</entry>
</search>