java中的单例模式是什么 什么是单例模式
本篇文章给大家谈谈java中的单例模式是什么,以及什么是单例模式对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。
什么是单例模式
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。
通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。
要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。
使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。
扩展资料:
优缺点:
优点
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
参考资料:百度百科---单例模式
java中的单例模式的代码怎么写
我从我的博客里把我的文章粘贴过来吧,对于单例模式模式应该有比较清楚的解释:
单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例。
一般说来,单例模式通常有以下几种:
1.饥汉式单例
public class Singleton{
private Singleton(){};
private static Singleton instance= new Singleton();
public static Singleton getInstance(){
return instance;
}
}
这是最简单的单例,这种单例最常见,也很可靠!它有个唯一的缺点就是无法完成延迟加载——即当系统还没有用到此单例时,单例就会被加载到内存中。
在这里我们可以做个这样的测试:
将上述代码修改为:
public class Singleton{
private Singleton(){
System.out.println("createSingleton");
};
private static Singleton instance= new Singleton();
public static Singleton getInstance(){
return instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
而我们在另外一个测试类中对它进行测试(本例所有测试都通过Junit进行测试)
public class TestSingleton{
@Test
public void test(){
Singleton.testSingleton();
}
}
输出结果:
createSingleton
CreateString
我们可以注意到,在这个单例中,即使我们没有使用单例类,它还是被创建出来了,这当然是我们所不愿意看到的,所以也就有了以下一种单例。
2.懒汉式单例
public class Singleton1{
private Singleton1(){
System.out.println("createSingleton");
}
private static Singleton1 instance= null;
public static synchronized Singleton1 getInstance(){
return instance==null?new Singleton1():instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
上面的单例获取实例时,是需要加上同步的,如果不加上同步,在多线程的环境中,当线程1完成新建单例操作,而在完成赋值操作之前,线程2就可能判
断instance为空,此时,线程2也将启动新建单例的操作,那么多个就出现了多个实例被新建,也就违反了我们使用单例模式的初衷了。
我们在这里也通过一个测试类,对它进行测试,最后面输出是
CreateString
可以看出,在未使用到单例类时,单例类并不会加载到内存中,只有我们需要使用到他的时候,才会进行实例化。
这种单例解决了单例的延迟加载,但是由于引入了同步的关键字,因此在多线程的环境下,所需的消耗的时间要远远大于第一种单例。我们可以通过一段测试代码来说明这个问题。
public class TestSingleton{
@Test
public void test(){
long beginTime1= System.currentTimeMillis();
for(int i=0;i<100000;i++){
Singleton.getInstance();
}
System.out.println("单例1花费时间:"+(System.currentTimeMillis()-beginTime1));
long beginTime2= System.currentTimeMillis();
for(int i=0;i<100000;i++){
Singleton1.getInstance();
}
System.out.println("单例2花费时间:"+(System.currentTimeMillis()-beginTime2));
}
}
最后输出的是:
单例1花费时间:0
单例2花费时间:10
可以看到,使用第一种单例耗时0ms,第二种单例耗时10ms,性能上存在明显的差异。为了使用延迟加载的功能,而导致单例的性能上存在明显差异,
是不是会得不偿失呢?是否可以找到一种更好的解决的办法呢?既可以解决延迟加载,又不至于性能损耗过多,所以,也就有了第三种单例:
3.内部类托管单例
public class Singleton2{
private Singleton2(){}
private static class SingletonHolder{
private static Singleton2 instance=new Singleton2();
}
private static Singleton2 getInstance(){
return SingletonHolder.instance;
}
}
在这个单例中,我们通过静态内部类来托管单例,当这个单例被加载时,不会初始化单例类,只有当getInstance方法被调用的时候,才会去加载
SingletonHolder,从而才会去初始化instance。并且,单例的加载是在内部类的加载的时候完成的,所以天生对线程友好,而且也不需要
synchnoized关键字,可以说是兼具了以上的两个优点。
4.总结
一般来说,上述的单例已经基本可以保证在一个系统中只会存在一个实例了,但是,仍然可能会有其他的情况,导致系统生成多个单例,请看以下情况:
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance= new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
通过一段代码来测试:
@Test
public void test() throws Exception{
Singleton3 s1= null;
Singleton3 s2= Singleton3.getInstance();
//1.将实例串行话到文件
FileOutputStream fos= new FileOutputStream("singleton.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
//2.从文件中读取出单例
FileInputStream fis= new FileInputStream("singleton.txt");
ObjectInputStream ois= new ObjectInputStream(fis);
s1=(Singleton3) ois.readObject();
if(s1==s2){
System.out.println("同一个实例");
}else{
System.out.println("不是同一个实例");
}
}
输出:
不是同一个实例
可以看到当我们把单例反序列化后,生成了多个不同的单例类,此时,我们必须在原来的代码中加入readResolve()函数,来阻止它生成新的单例
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance= new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
//阻止生成新的实例
public Object readResolve(){
return SingletonHolder.instance;
}
}
再次测试时,就可以发现他们生成的是同一个实例了。
JAVA单例模式有哪些
一、懒汉式单例
在类加载的时候不创建单例实例。只有在第一次请求实例的时候的时候创建,并且只在第一次创建后,以后不再创建该类的实例。
public class LazySingleton{
/**
*私有静态对象,加载时候不做初始化
*/
private static LazySingleton m_intance=null;
/**
*私有构造方法,避免外部创建实例
*/
private LazySingleton(){
}
/**
*静态工厂方法,返回此类的唯一实例.
*当发现实例没有初始化的时候,才初始化.
*/
synchronized public static LazySingleton getInstance(){
if(m_intance==null){
m_intance=new LazySingleton();
}
return m_intance;
}
}
二、饿汉式单例
在类被加载的时候,唯一实例已经被创建。
public class EagerSingleton{
/**
*私有的(private)唯一(static final)实例成员,在类加载的时候就创建好了单例对象
*/
private static final EagerSingleton m_instance= new EagerSingleton();
/**
*私有构造方法,避免外部创建实例
*/
private EagerSingleton(){
}
/**
*静态工厂方法,返回此类的唯一实例.
*@return EagerSingleton
*/
public static EagerSingleton getInstance(){
return m_instance;
}
}
**************************************************************************************懒汉方式,指全局的单例实例在第一次被使用时构建;
饿汉方式,指全局的单例实例在类装载时构建
**************************************************************************************
三、登记式单例
这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。
public class RegSingleton{
/**
*登记薄,用来存放所有登记的实例
*/
private static Map<String, RegSingleton> m_registry= new HashMap();
//在类加载的时候添加一个实例到登记薄
static{
RegSingleton x= new RegSingleton();
m_registry.put(x.getClass().getName(), x);
}
/**
*受保护的默认构造方法
*/
protected RegSingleton(){
}
/**
*静态工厂方法,返回指定登记对象的唯一实例;
*对于已登记的直接取出返回,对于还未登记的,先登记,然后取出返回
*@param name
*@return RegSingleton
*/
public static RegSingleton getInstance(String name){
if(name== null){
name="RegSingleton";
}
if(m_registry.get(name)== null){
try{
m_registry.put(name,(RegSingleton) Class.forName(name).newInstance());
} catch(InstantiationException e){
e.printStackTrace();
} catch(IllegalAccessException e){
e.printStackTrace();
} catch(ClassNotFoundException e){
e.printStackTrace();
}
}
return m_registry.get(name);
}
/**
*一个示意性的商业方法
*@return String
*/
public String about(){
return"Hello,I am RegSingleton!";
}
}
java中的单例模式是什么和什么是单例模式的问题分享结束啦,以上的文章解决了您的问题吗?欢迎您下次再来哦!