深入单例模式 java,深入单例模式四

本文探讨了Java中的单例模式实现,包括考虑多线程、类加载器和序列化的情况。通过示例代码展示了如何创建一个线程安全的单例类,并解释了如何使用`readResolve()`方法确保在序列化和反序列化后仍保持单例状态。此外,还提供了一个测试用例来验证单例的唯一性。
摘要由CSDN通过智能技术生成

Java代码 icon_copy.gif

privatestaticClass getClass(String classname)

throwsClassNotFoundException {

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if(classLoader ==null)

classLoader = Singleton.class.getClassLoader();

return(classLoader.loadClass(classname));

}

}

private static Class getClass(String classname)

throws ClassNotFoundException {

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if(classLoader == null)

classLoader = Singleton.class.getClassLoader();

return (classLoader.loadClass(classname));

}

}

这个方法会尝试把当前的线程与那个类载入器相关联;如果classloader为null,这个方法会使用与装入单例类基类的那个类载入器。这个方法可以用Class.forName()代替。

序列化

如果你序列化一个单例类,然后两次重构它,那么你就会得到那个单例类的两个实例,除非你实现readResolve()方法,像下面这样:

例12 一个可序列化的单例类

Java代码 icon_copy.gif

importorg.apache.log4j.Logger;

publicclassSingletonimplementsjava.io.Serializable {

publicstaticSingleton INSTANCE =newSingleton();

protectedSingleton() {

// Exists only to thwart instantiation.

}

privateObject readResolve() {

returnINSTANCE;

}

}

import org.apache.log4j.Logger;

public class Singleton implements java.io.Serializable {

public static Singleton INSTANCE = new Singleton();

protected Singleton() {

// Exists only to thwart instantiation.

}

private Object readResolve() {

return INSTANCE;

}

}

上面的单例类实现从readResolve()方法中返回一个唯一的实例;这样无论Singleton类何时被重构,它都只会返回那个相同的单例类实例。

例13测试了例12的单例类:

例13 测试一个可序列化的单例类

Java代码 icon_copy.gif

importjava.io.*;

importorg.apache.log4j.Logger;

importjunit.framework.Assert;

importjunit.framework.TestCase;

publicclassSingletonTestextendsTestCase {

privateSingleton sone =null, stwo =null;

privatestaticLogger logger = Logger.getRootLogger();

publicSingletonTest(String name) {

super(name);

}

publicvoidsetUp() {

sone = Singleton.INSTANCE;

stwo = Singleton.INSTANCE;

}

publicvoidtestSerialize() {

logger.info("testing singleton serialization...");

      writeSingleton();

Singleton s1 = readSingleton();

Singleton s2 = readSingleton();

Assert.assertEquals(true, s1 == s2);   }

privatevoidwriteSingleton() {

try{

FileOutputStream fos =newFileOutputStream("serializedSingleton");

ObjectOutputStream oos =newObjectOutputStream(fos);

Singleton s = Singleton.INSTANCE;

oos.writeObject(Singleton.INSTANCE);

oos.flush();

}

catch(NotSerializableException se) {

logger.fatal("Not Serializable Exception: "+ se.getMessage());

}

catch(IOException iox) {

logger.fatal("IO Exception: "+ iox.getMessage());

}

}

privateSingleton readSingleton() {

Singleton s =null;

try{

FileInputStream fis =newFileInputStream("serializedSingleton");

ObjectInputStream ois =newObjectInputStream(fis);

s = (Singleton)ois.readObject();

}

catch(ClassNotFoundException cnf) {

logger.fatal("Class Not Found Exception: "+ cnf.getMessage());

}

catch(NotSerializableException se) {

logger.fatal("Not Serializable Exception: "+ se.getMessage());

}

catch(IOException iox) {

logger.fatal("IO Exception: "+ iox.getMessage());

}

returns;

}

publicvoidtestUnique() {

logger.info("testing singleton uniqueness...");

Singleton another =newSingleton();

logger.info("checking singletons for equality");

Assert.assertEquals(true, sone == stwo);

}

}

import java.io.*;

import org.apache.log4j.Logger;

import junit.framework.Assert;

import junit.framework.TestCase;

public class SingletonTest extends TestCase {

private Singleton sone = null, stwo = null;

private static Logger logger = Logger.getRootLogger();

public SingletonTest(String name) {

super(name);

}

public void setUp() {

sone = Singleton.INSTANCE;

stwo = Singleton.INSTANCE;

}

public void testSerialize() {

logger.info("testing singleton serialization...");

writeSingleton();

Singleton s1 = readSingleton();

Singleton s2 = readSingleton();

Assert.assertEquals(true, s1 == s2); }

private void writeSingleton() {

try {

FileOutputStream fos = new FileOutputStream("serializedSingleton");

ObjectOutputStream oos = new ObjectOutputStream(fos);

Singleton s = Singleton.INSTANCE;

oos.writeObject(Singleton.INSTANCE);

oos.flush();

}

catch(NotSerializableException se) {

logger.fatal("Not Serializable Exception: " + se.getMessage());

}

catch(IOException iox) {

logger.fatal("IO Exception: " + iox.getMessage());

}

}

private Singleton readSingleton() {

Singleton s = null;

try {

FileInputStream fis = new FileInputStream("serializedSingleton");

ObjectInputStream ois = new ObjectInputStream(fis);

s = (Singleton)ois.readObject();

}

catch(ClassNotFoundException cnf) {

logger.fatal("Class Not Found Exception: " + cnf.getMessage());

}

catch(NotSerializableException se) {

logger.fatal("Not Serializable Exception: " + se.getMessage());

}

catch(IOException iox) {

logger.fatal("IO Exception: " + iox.getMessage());

}

return s;

}

public void testUnique() {

logger.info("testing singleton uniqueness...");

Singleton another = new Singleton();

logger.info("checking singletons for equality");

Assert.assertEquals(true, sone == stwo);

}

}

前面这个测试案例序列化例12中的单例类,并且两次重构它。然后这个测试案例检查看是否被重构的单例类实例是同一个对象。下面是测试案例的输出:

Java代码 icon_copy.gif

Buildfile: build.xml

init:

[echo] Build20030422(22-04-200311:32)

compile:

run-test-text:

[java] .INFO main: testing singleton serialization...

[java] .INFO main: testing singleton uniqueness...

[java] INFO main: checking singletonsforequality

[java] Time:0.1

[java] OK (2tests)

Buildfile: build.xml

init:

[echo] Build 20030422 (22-04-2003 11:32)

compile:

run-test-text:

[java] .INFO main: testing singleton serialization...

[java] .INFO main: testing singleton uniqueness...

[java] INFO main: checking singletons for equality

[java] Time: 0.1

[java] OK (2 tests)

单例模式结束语

单例模式简单却容易让人迷惑,特别是对于Java的开发者来说。在这篇文章中,作者演示了Java开发者在顾及多线程、类载入器和序列化情况如何实现单例模式。作者也展示了你怎样才能实现一个单例类的注册表,以便能够在运行期指定单例类。

posted on 2008-05-05 22:12 bcterry 阅读(38) 评论(0)  编辑  收藏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值