打破传统的单身人士

时间:2015-02-06 06:40:49

标签: java multithreading singleton legacy-code

我们已将所有遗留代码打包到一个库中,新版本的代码会在需要时调用遗留代码;虽然这种方法很好,但目前我们处于困扰之中,因为遗留代码的一部分有线程不安全的单例,而调用它们的新代码期望它们是线程安全的;我们负担不起同步块,因为当负载超过一定数量时会阻塞系统。思想会接受你的意见。谢谢!

修改 这些单例是懒惰的,没有对null实例进行同步和双重检查:

 public static Parser getInstance() {
    Parser p = null;

    try {
        if (instance == null) {
            instance = new Parser(...);
        }

    } catch (Exception x) {
        ...
    }
    return p;
 }

并且此代码至少已有8年的历史,我们无法修复它们。

2 个答案:

答案 0 :(得分:0)

正如上面评论中提到的,你应该简单地修复这些类(这是一个简单的修复!)。也就是说,假设您无法触及此代码,您可以继承它并“覆盖”(实际上它被称为“隐藏”,因为该方法是静态的)getInstance()。这只会修复损坏的部分,并且会为其他部分保持相同的逻辑。

顺便说一句,如果您决定使用双重空检查来实现单例,那么您不仅必须同步最里面的检查,还必须将instance声明为volatile

有更好的方法来实现懒惰和急切的单例(静态类,内部助手类和枚举),请确保在选择之前评估所有选项。

答案 1 :(得分:0)

如果你有一个非线程安全的对象,并且工厂方法返回一个单例,你别无选择,只能进行同步。

您需要更改构造新对象的工厂方法(或创建一个新方法,如果您不能编辑原始代码)。如果这太昂贵了(并且不要假设它是,直到你测试它),看看哪些方面是昂贵的,也许一些对象的依赖关系仍然可以是单例。

这里没有神奇的解决方案。

但是......我即将告诉你我在类似情况下做过的黑客行为。但这是最后的度假村,无论如何可能无法正常工作。曾经有一个Web应用程序由许多servlet组成,这些servlet包含有效的全局和局部变量,作为成员变量。写它的那个人并没有意识到servlet的成员是单个实例。该应用程序使用1个客户端进行测试,但多个连接失败。我们需要快速修复。我让servlet按照自己的意思构建自己。当调用doGet和doPost方法时,我得到了servlet来克隆自己并将请求传递给克隆。这复制了"全球"成员并向请求提出了新的未初始化成员的请求。但是,它有问题。所以不要这样做。只需修复你的代码。 :)