0

We have packaged all our legacy code into a library and the new version of the code calls the legacy code as and when required; Though this approach is good, currently we are in a spot of bother as part of the legacy code has thread-unsafe singletons whereas the newer code calling them expect them to be thread-safe; we cannot afford to have synchronized blocks as that will clog the system when the load goes beyond certain number. Thought will take your inputs. Thanks!

Edit: These singletons are lazy ones without synchronized and double-checks on null instance:

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

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

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

and this code is at least 8 years old, we cannot fix them.

Venkatesh Laguduva
  • 13,448
  • 6
  • 33
  • 45
  • 1
    What do you mean "are not thread safe" ? are these singleton stateful? or are they "unsafe" regarding the way they're implemented (which can create more than one instance) ? without further explanation and code examples it'd difficult to answer. – Nir Alfasi Feb 06 '15 at 06:44
  • code example will help everyone understand your question. – Dongqing Feb 06 '15 at 06:57
  • How 'legacy' is the legacy code? It sounds like it is fundamentally broken (or simply not designed for multi-threaded access), as singletons should always be thread-safe. Do you have any scope to change that code? – Andy Turner Feb 06 '15 at 07:09
  • 2
    If the legacy code is broken, why not fix it? – user253751 Feb 06 '15 at 07:26
  • I agree with immibis. Incidentally, [this book](http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/) is full of useful advice on cleaning up and improving an existing legacy codebase, without breaking things. – Sneftel Feb 06 '15 at 07:44
  • The same question. Why you wouldn't rewrite exactly that class which contains getInstance() method and patch your jar(?) file by the fixed one? BTW, here is a good article about safe publication in java: http://shipilev.net/blog/2014/safe-public-construction/ – AnatolyG Feb 06 '15 at 10:54

2 Answers2

0

As was mentioned above in the comments, you should simply fix these classes (that's an easy fix!). That said, assuming you cannot touch this code, you can inherit from it and "override" (actually it's called "hiding" since the method is static) getInstance(). That would fix only the broken part and will maintain the same logic for the other parts.

BTW, if you decide to implement a singleton with the double null check, not only that you have to synchronize the innermost check, you also have to declare instance as volatile.

There are better ways to implement both lazy and eager singleton (static class, inner helper class and enum), make sure to asses all the options before you choose one.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • you cant override a static method. but he might be able to implement all this in another class anyway. or nuke the original, at source level or class file level. – slipperyseal Feb 06 '15 at 22:13
  • @SlipperySeal you're right, it's called hiding - not overriding. But it's just terminology cause the main idea stays the same. – Nir Alfasi Feb 07 '15 at 01:11
  • ahh. cool. i didn't even realize method hiding was a thing. and iv been writing java for a long time. :) – slipperyseal Feb 08 '15 at 09:59
0

if you have an object which is not thread safe, and the factory method returns a singleton, you have no choice but to synchronise.

you will need to change the factory method (or create a new one, if you can't edit the original code) which constructs new objects. if this is too expensive (and don't just assume it is, until you test it), look into which aspects of that are expensive and maybe some of the object's dependencies can still be singletons.

there is no magic solution here.

but.. i am about to tell you about a hack I did once when I was in a similar situation. but this is LAST RESORT and may not work in your case anyway. i was once handed a web application consisting of many servlets which contained both effectively global and local variables, as member variables. the guy who wrote it didn't realise the members of a servlet were single instance. the app worked in testing with 1 client but failed with multiple connections. we needed a fix fast. i let the servlets construct themselves as written. as the doGet and doPost methods were called, i got the servlet to clone itself and pass requests down to the clone. this copied the "global" members and gave the request fresh uninitialised members to the request. but, it's problematic. so don't do it. just fix your code. :)

slipperyseal
  • 2,728
  • 1
  • 13
  • 15
  • your assessment is very close to what I have got to fix; the real issue lies behind a factory class which caches certain 'thread-unsafe' objects and returns them whoever ask for them. I am going to disable that cache so that newer objects get created(I am not cloning as your hack) for every request! – Venkatesh Laguduva Feb 09 '15 at 09:22