当前位置:  开发笔记 > 编程语言 > 正文

这个Java单例可以在WebSphere 6中重复重建吗?

如何解决《这个Java单例可以在WebSphere6中重复重建吗?》经验,为你挑选了5个好方法。

我正在尝试追踪我们系统中的问题,以下代码让我担心.主servlet中的doPost()方法发生以下情况(名称已更改以保护有罪):

...
if(Single.getInstance().firstTime()){
   doPreperations();
}
normalResponse();
...

单身'单身'看起来像这样:

private static Single theInstance = new Single();

private Single() {
...load properties...
}

public static Single getInstance() {
    return theInstance;
}

通过这种方式设置为使用静态初始化程序而不是在getInstance()方法中检查null theInstance,是否可以一次又一次地重建?

PS - 我们正在使用Java 1.4上的App运行WebSphere 6



1> Chris Marast..:

我在Sun的网站上发现了这个:

不同类装载机同时装载多个单身人士

当两个类加载器加载一个类时,实际上有两个类的副本,每个类都可以拥有自己的Singleton实例.这在某些servlet引擎(例如iPlanet)中运行的servlet中尤为重要,其中每个servlet默认使用自己的类加载器.实际上,访问联合Singleton的两个不同的servlet将获得两个不同的对象.

多个类加载器比您想象的更常见.当浏览器从网络加载类以供applet使用时,它们为每个服务器地址使用单独的类加载器.类似地,Jini和RMI系统可以为它们下载类文件的不同代码库使用单独的类加载器.如果您自己的系统使用自定义类加载器,则可能会出现所有相同的问题.

如果由不同的类加载器加载,则具有相同名称的两个类(甚至相同的包名称)将被视为不同 - 即使实际上它们是逐字节的同一个类.不同的类加载器表示区分类的不同名称空间(即使类的名称相同),因此这两个 MySingleton类实际上是不同的.(请参阅参考资料中的"类加载器作为命名空间机制".)由于两个Singleton对象属于同一名称的两个类,因此乍一看它会出现两个同一类的Singleton对象.

引用.

除了上述问题,如果firstTime()不同步,您也可能遇到线程问题.



2> Epaga..:

不,它不会一次又一次地建造.它是静态的,因此只有在类加载器第一次触摸类时才会构造一次.

唯一的例外 - 如果您碰巧有多个类加载器.

(来自GeekAndPoke):

替代文字



3> matt b..:

正如其他人所提到的,静态初始化程序只能为每个类加载器运行一次.

我要看一看的是firstTime()方法 - 为什么不能doPreparations()在单例本身内处理工作?

听起来像一堆讨厌的依赖.



4> Jevgeni Kaba..:

使用静态初始化程序和延迟初始化之间绝对没有区别.事实上,搞乱延迟初始化要容易得多,这也会强制实现同步.JVM保证静态初始化程序始终在访问类之前运行,并且只会发生一次.

这就是说JVM不保证你的类只加载一次.但是,即使它被加载多次,您的Web应用程序仍将只看到相关的单例,因为它将加载到Web应用程序类加载器或其父级中.如果部署了多个Web应用程序,则将为每个应用程序调用firstTime()一次.

要检查的最明显的事情是firstTime()需要同步,并且在退出该方法之前设置firstTime标志.


看不出这与问题有什么关系.在静态初始化程序中初始化是完全线程安全的.JVM在进行初始化时会锁定类,因此并发访问必须等待.

5> mjlee..:

不,它不会创建"单个"的多个副本.(稍后将访问类加载器问题)

您概述的实现在Briant Goetz的书" Java Concurrency in Practice " 中被描述为"Eager Initialization ".

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {
        return theInstance;
    }
}

但是,代码不是你想要的.您的代码在创建实例后尝试执行延迟初始化.这要求所有客户端库在使用之前执行'firstTime()/ doPreparation()'.您将依赖客户端做正确的事情,使代码非常脆弱.

您可以按如下所示修改代码,这样就不会有任何重复的代码.

public class Single
{
    private static Single theInstance = new Single();

    private Single() 
    { 
        // load properties
    }

    public static Single getInstance() 
    {   
        // check for initialization of theInstance
        if ( theInstance.firstTime() )
           theInstance.doPreparation();

        return theInstance;
    }
}

不幸的是,这是一个很糟糕的初始化实现,这在并发环境(如J2EE容器)中不起作用.

有很多关于Singleton初始化的文章,特别是关于内存模型的文章. JSR 133解决了Java 1.5和1.6中Java内存模型的许多弱点.

使用Java 1.5和1.6,您有几种选择,Joshua Bloch 在" Effective Java " 一书中提到了它们.

    渴望初始化,如上所述[EJ第3项]

    Lazy Initalization Holder Class Idiom [EJ Item 71]

    枚举类型[EJ第3项]

    带有"易变"静态区域的双重检查锁定[EJ Item 71]

解决方案3和4仅适用于Java 1.5及更高版本.所以最好的解决方案是#2.

这是伪实现.

public class Single
{
    private static class SingleHolder
    {
        public static Single theInstance = new Single();
    }

    private Single() 
    { 
        // load properties
        doPreparation();
    }

    public static Single getInstance() 
    {
        return SingleHolder.theInstance;
    }
}

请注意,'doPreparation()'在构造函数内部,因此您可以保证获得正确初始化的实例.此外,您正在回顾JVM的延迟类加载,并且不需要任何同步'getInstance()'.

有一点你注意到静态字段theInstance 不是'final'. 关于Java Concurrency的示例没有'final',但EJ没有.也许詹姆斯可以为他的"类加载器"和"最终"要求添加更多颜色以保证正确性,

话虽如此,使用'静态最终'会产生副作用.当Java编译器看到'static final'并试图尽可能地内联它时,它是非常积极的.这是Jeremy Manson在博客上发表的.

这是一个简单的例子.

档案:A.java

public class A
{
    final static String word = "Hello World";
}

档案:B.java

public class B
{
    public static void main(String[] args) {
        System.out.println(A.word);
    }
}

在编译A.java和B.java之后,将A.java更改为以下内容.

档案:A.java

public class A
{
    final static String word = "Goodbye World";
}

您重新编译'A.java'并重新运行B.class.你会得到的输出是

Hello World

至于类加载器问题,答案是肯定的,你可以在多个类加载器中有多个Singleton实例.您可以在维基百科上找到更多信息.Websphere上还有一篇特定的文章.

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有