How do I use the Java API in a Thread-Safe Manner?

Discussion in 'Java' started by Al Koch, Jun 22, 2005.

  1. Al Koch

    Al Koch Guest

    Hello,

    I am writing a Java servlet and am new to coding for thread synchronization.
    I suspect that there must be an "obvious" solution to the following problem
    but after sevearl days of research I can't find it!

    It is my understanding that, in general, the J2SE 1.4 API is *not*
    thread-safe. There are some APIs where the Sun documentation states that a
    Class's methods are thread-safe (such as StringBuffer) but in general, most
    of the text and web search references I have found have stated that the API
    in general is not thread-safe. That means that there must be at least one
    (and it's probably most) API that is not thread-safe and let me just call
    such an unsafe method "UnsafeAPI()". My question is, how do I use
    UnsafeAPI() and write code to make my code thread-safe?

    For example, if I have the following code:

    public final class MyClass {
    private int i;
    private int j;
    private int k;

    public finale void MyMethod(int i, int j, int k)
    {
    this.i = i;
    this.j = j;
    this.k = k;
    }
    }

    I have a thread safety issue here. Assignement to an int is atomic so no
    one of the three assignment statements in MyMethod() can be interrupted by
    another thread. However, the *sequence of all three assignments* certainly
    can be interrupted so I am vulnerable to a synchronization issue. I could
    either fix this proiblem by adding the "sychronized" modifier to the
    MyMethod declaration, or I could do the following:


    public final class MyClass {
    private int i;
    private int j;
    private int k;

    public finale void MyMethod(int i, int j, int k)
    {
    synchronize(this) {
    this.i = i;
    this.j = j;
    this.k = k;
    }
    }
    }

    At this point I am thread safe. However, assume that I also need to call
    UnsafeAPI(). Now my code looks like:

    public final class MyClass {
    private int i;
    private int j;
    private int k;

    public finale void MyMethod(int i, int j, int k)
    {
    synchronize(this) {
    this.i = i;
    this.j = j;
    this.k = k;
    UnsafeAPI(); // this is any J2SE 1.4 API that, in general, is not
    thread safe!
    }
    }
    }

    The synchronize(this) guarantees that no other thread can enter *my code
    block* in MyMethod() but (as far as I can tell) it in no way prevents
    another thread from entering UnsafeAPI() from another block of code, either
    in my servlet or even in another application altogether.

    There must be some way to block a thread from entering UnsafeAPI() because
    otherwise it would be impossible to write a thread safe application, but I
    sure can't find a way to do this. Can someone explain how this is done? If
    you can also tell me how/where you learned how to do this I would be very
    interested because I can't locate any such information!)

    Thank you!
    Al

    Al Koch, Jun 22, 2005
    #1
    1. Advertising

  2. Al Koch

    Chris Head Guest

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Al Koch wrote:
    [snip]
    > The synchronize(this) guarantees that no other thread can enter *my code
    > block* in MyMethod() but (as far as I can tell) it in no way prevents
    > another thread from entering UnsafeAPI() from another block of code, either
    > in my servlet or even in another application altogether.
    >
    > There must be some way to block a thread from entering UnsafeAPI() because
    > otherwise it would be impossible to write a thread safe application, but I
    > sure can't find a way to do this. Can someone explain how this is done? If
    > you can also tell me how/where you learned how to do this I would be very
    > interested because I can't locate any such information!)
    >
    > Thank you!
    > Al
    >
    >
    >
    >


    Hello,
    It is true that most of the Java API is not thread-safe. However, it is
    ALSO true that most of the Java API is implemented as member functions
    in classes. Thus, your example of UnsafeAPI() would probably be a member
    function on a class. Generally, while it is NOT safe to call UnsafeAPI()
    multiple times simultaneously on the SAME instance of the class, it IS
    safe to call it simultaneously on DIFFERENT INSTANCES. At this point,
    you must realize that your own application probably has essentially
    complete control of the specific object you're interested in, so it's
    fairly feasible to synchronize those calls.

    If you will be calling methods on an object of a given API class from
    various of your own objects in various of your own threads, it might be
    better to synchronize on the object of the API class rather than on
    "this". That way calls to the API object from different of your own
    objects will all be serialized against each other (and become safe).

    For example:

    class MyA {
    UnsafeAPIObject obj;
    MyA(UnsafeAPIObject o) {
    obj = 0;
    }
    public doSomething() {
    synchronized(obj) {
    obj.doStuff();
    }
    }
    }

    class MyB {
    UnsafeAPIObject obj;
    MyB(UnsafeAPIObject o) {
    obj = 0;
    }
    public doSomething() {
    synchronized(obj) {
    obj.doStuff();
    }
    }
    }

    ....

    UnsafeAPIObject obj = new UnsafeAPIObject();
    MyA a = new MyA(obj);
    MyB b = new MyB(obj);
    a.doSomething();
    <in some other thread>
    b.doSomething();

    Here, the obj.doStuff() calls will be properly synchronized. Had you
    replaced both synchronized(obj) blocks with synchronized(this), you
    would have had no synchronization, because thread 1 would sync on (a)
    and thread 2 would sync on (b), so they would not block each other. I
    believe it's generally recommended to synchronize on the object you're
    calling as a convention.

    Hope this clears things up (and that I haven't said anything too wrong)

    Chris
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.1 (MingW32)

    iD8DBQFCuNL+gxSrXuMbw1YRAoVhAJ9k5O12TzFUweVs0eiSFCTTltADhQCcCf3r
    GFmvh7D4UjJRKByL9gscOZ4=
    =ROSq
    -----END PGP SIGNATURE-----
    Chris Head, Jun 22, 2005
    #2
    1. Advertising

  3. Al Koch

    Al Koch Guest

    Hi Chris,

    Thanks very much for your reply. I have a couple of follow on questions.

    > Here, the obj.doStuff() calls will be properly synchronized. Had you
    > replaced both synchronized(obj) blocks with synchronized(this), you
    > would have had no synchronization, because thread 1 would sync on (a)
    > and thread 2 would sync on (b), so they would not block each other. I
    > believe it's generally recommended to synchronize on the object you're
    > calling as a convention.
    >


    I didn't state it in my question but I agree that "most of the time" the API
    would be called on an instance of a "Java API class" and I suspected that I
    ought to be able to synch control of my object instances (I didn't want to
    say that in the question so that I could get a "wide open" response.)
    However, there are (at least!) two things that confuse me:

    1) How "safe" is the new operator? Here is a (simplifed) piece of code:

    public static final String appendTrailingBackslash(String sStr)
    {
    sbStr = new StringBuffer(sStr);
    sbStr.append('\\');
    return(sbStr.toString());
    }

    Do I ever need to worry about synch'ing the new and if so, how would I do
    that in the above example. For instance, the following wouldn't accomplish
    anything (assuming it is even necesarry to protect the new):

    public static final String appendTrailingBackslash(String sStr)
    {
    Object lockObject = new Integer(666);
    StringBuffer sbStr = null;
    synchronized(lockObject) {
    sbStr = new StringBuffer(sStr);
    }
    sbStr.append('\\');
    return(sbStr.toString());
    }


    2) We agree that I should be able to synch my object instances but what
    about a static member function in the API. For example,

    MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");

    In this example, getInstance() is a static member. How in the world do you
    protect this call? (I realize that one might argue that getInstance()
    "appears" to only "lookup" something and as such needs no synchronization
    but 1) how are we supposed to determine what a static member function does
    internally and 2) if we have a static member function that we do need to
    worry about, how would that be protected?)

    Thanks again for your help.

    Al.
    Al Koch, Jun 22, 2005
    #3
  4. Al Koch

    Eric Sosman Guest

    Al Koch wrote:
    > Hi Chris,
    >
    > Thanks very much for your reply. I have a couple of follow on questions.
    >
    >
    >>Here, the obj.doStuff() calls will be properly synchronized. Had you
    >>replaced both synchronized(obj) blocks with synchronized(this), you
    >>would have had no synchronization, because thread 1 would sync on (a)
    >>and thread 2 would sync on (b), so they would not block each other. I
    >>believe it's generally recommended to synchronize on the object you're
    >>calling as a convention.

    >
    > I didn't state it in my question but I agree that "most of the time" the API
    > would be called on an instance of a "Java API class" and I suspected that I
    > ought to be able to synch control of my object instances (I didn't want to
    > say that in the question so that I could get a "wide open" response.)
    > However, there are (at least!) two things that confuse me:
    >
    > 1) How "safe" is the new operator? Here is a (simplifed) piece of code:
    >
    > public static final String appendTrailingBackslash(String sStr)
    > {
    > sbStr = new StringBuffer(sStr);
    > sbStr.append('\\');
    > return(sbStr.toString());
    > }
    >
    > Do I ever need to worry about synch'ing the new [...]


    No, it's not necessary to synchronize the `new' operator.
    You probably need to synchronize access to `sbStr', which seems
    to be a static member of the class containing this method --
    but maybe that was just a typo.

    > 2) We agree that I should be able to synch my object instances but what
    > about a static member function in the API. For example,
    >
    > MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");
    >
    > In this example, getInstance() is a static member. How in the world do you
    > protect this call? (I realize that one might argue that getInstance()
    > "appears" to only "lookup" something and as such needs no synchronization
    > but 1) how are we supposed to determine what a static member function does
    > internally and 2) if we have a static member function that we do need to
    > worry about, how would that be protected?)


    There's no effective way to synchronize access to an
    accessible static method -- you could synchronize on the
    method's class or on any other agreed-upon object, but you'd
    need to rely on all callers doing the synchronization, which
    is hard to enforce.

    Perhaps the JavaDoc should explicitly say "getInstance()
    is safe to use in multi-threaded code," but I think we can
    probably take that for granted. If the static method operates
    on thread-unsafe objects, the method itself should take care
    of synchronizing appropriately. For example, a static factory
    method that maintains a cache of frequently-used objects may
    need to synchronize its own access to the cache, but the caller
    of the factory method shouldn't need to worry.

    The idea in Java is to protect the object, not the code.
    (Disclaimer: Some months back there was a heated discussion of
    this point, and somebody took exception to this view of things.
    Of course, *he* was wrong.) If you think about the object
    being manipulated rather than about the code that does the
    manipulations, things may be a lot less confusing -- and maybe
    even less threatening.

    --
    Eric Sosman, Jun 22, 2005
    #4
  5. Al Koch

    Al Koch Guest

    Hi Eric,

    Thanks for your response.

    > No, it's not necessary to synchronize the `new' operator.
    > You probably need to synchronize access to `sbStr', which seems
    > to be a static member of the class containing this method --
    > but maybe that was just a typo.

    Yes, that was a typo; the code example should have shown sbStr as being
    declared as a local variable (which would make it it thread-safe, right?).
    You say that I don't need to synchronize the new opertaor. Can you tell me
    how you know this? I am not asking that question because I don't believe
    you but rather because I'm trying to find that "magic reference" that
    answers such questions! It seems that what I am asking is so fundamental
    ("what in the Java language and the J2SE API is thread-safe and how does a
    person know?") that the answer could be found in a hundred places but it
    seems like this question is one that no book or support site wants to deal
    with! So, how did you learn that the new operator is safe?

    > There's no effective way to synchronize access to an
    > accessible static method -- you could synchronize on the
    > method's class or on any other agreed-upon object, but you'd
    > need to rely on all callers doing the synchronization, which
    > is hard to enforce.


    Assuming for the moment that I'll depend on "evryone else" enforcing
    synchronization (which, since that means every other piece of Java code
    running in the same VM that I'm in, is silly!), how would I "synchronize on
    the method's class"? Using the example that I presented, how would you
    synchronize the following:

    MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");

    Would it be:

    MessageDigest dummyDigestObject = new MessageDigest;
    synchronize(dummyDigestObject) {
    MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");
    }

    > Perhaps the JavaDoc should explicitly say "getInstance()
    > is safe to use in multi-threaded code," but I think we can
    > probably take that for granted. If the static method operates
    > on thread-unsafe objects, the method itself should take care
    > of synchronizing appropriately. For example, a static factory
    > method that maintains a cache of frequently-used objects may
    > need to synchronize its own access to the cache, but the caller
    > of the factory method shouldn't need to worry.


    You are suggesting that we infer what the code is doing and that we can take
    for granted that the API is doing what needs to be done to protect the code.
    This is similar to a variety of posts that I've come across in a wide number
    of forums that expressive a great deal of frustration that the
    documentation is silent on so much of this. What you are saying is in line
    with much that I've read but (acknowleding that I'm still new to dealing
    with Threads in Java) this seems like a rather unsuitable way to go about
    building software! You aren't expressing much concern that this is all
    rather undocumented; can you help me understand why (if I am reading between
    the lines correctly) this isn't an issue of much concern for you?

    > The idea in Java is to protect the object, not the code.
    > (Disclaimer: Some months back there was a heated discussion of
    > this point, and somebody took exception to this view of things.
    > Of course, *he* was wrong.) If you think about the object
    > being manipulated rather than about the code that does the
    > manipulations, things may be a lot less confusing -- and maybe
    > even less threatening.


    That seems like a helpful "guiding principle".

    Thanks again for your comments.

    Al.
    Al Koch, Jun 22, 2005
    #5
  6. Al Koch

    Eric Sosman Guest

    Al Koch wrote:
    > Hi Eric,
    >
    > Thanks for your response.
    >
    >
    >> No, it's not necessary to synchronize the `new' operator.
    >>You probably need to synchronize access to `sbStr', which seems
    >>to be a static member of the class containing this method --
    >>but maybe that was just a typo.

    >
    > Yes, that was a typo; the code example should have shown sbStr as being
    > declared as a local variable (which would make it it thread-safe, right?).
    > You say that I don't need to synchronize the new opertaor. Can you tell me
    > how you know this? I am not asking that question because I don't believe
    > you but rather because I'm trying to find that "magic reference" that
    > answers such questions! It seems that what I am asking is so fundamental
    > ("what in the Java language and the J2SE API is thread-safe and how does a
    > person know?") that the answer could be found in a hundred places but it
    > seems like this question is one that no book or support site wants to deal
    > with! So, how did you learn that the new operator is safe?


    `new' itself is safe for the same reason `+' is safe:
    it's just an operator; it has no internal state of its own
    that needs protection.

    It's possible to write an unsafe constructor, but that's
    a somewhat different matter. If a constructor is unsafe there's
    really not much you can do about it; constructors are a lot like
    static methods in this regard. However, I can think of only two
    ways a constructor can be unsafe (perhaps the experts will chime
    in with more):

    - While building the new object, the constructor could
    manipulate some other object that could be accessible
    to another thread. For example, a constructor that
    maintained a "registry" of constructed instances might
    manipulate the registry without synchronizing. I'd
    consider this a bug in the constructor.

    - The constructor could put a reference to the new object
    someplace where another thread could find it, and then
    proceed to manipulate the new object without synchronizing.
    Again, I'd consider this a constructor bug.

    The typical constructor that just massages the object under
    construction and doesn't export any references to it is safe
    because it's working on an object that no other thread can
    (yet) get hold of.

    >> There's no effective way to synchronize access to an
    >>accessible static method -- you could synchronize on the
    >>method's class or on any other agreed-upon object, but you'd
    >>need to rely on all callers doing the synchronization, which
    >>is hard to enforce.

    >
    >
    > Assuming for the moment that I'll depend on "evryone else" enforcing
    > synchronization (which, since that means every other piece of Java code
    > running in the same VM that I'm in, is silly!), how would I "synchronize on
    > the method's class"? Using the example that I presented, how would you
    > synchronize the following:
    >
    > MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");
    >
    > Would it be:
    >
    > MessageDigest dummyDigestObject = new MessageDigest;
    > synchronize(dummyDigestObject) {
    > MessageDigest mdSHA1 = MessageDigest.getInstance("SHA-1");
    > }


    Any agreed-upon object would do, so long as all the, um,
    "synchronizers" have access to it. Your example as written
    won't work (no parameters to the constructor, and besides: the
    MessageDigest constructor is protected), but could be made to
    work. You'd still have something of a problem, though: if
    you're trying to ensure that only one thread at a time executes
    getInstance() you need to have them all synchronize on the same
    object; just creating and discarding a new one each time won't
    do the trick. That means you need an object that's "visible"
    to all the threads, not a thread-unique object for each of them.

    Any agreed-upon object would do, as I said before. You might
    choose System.out or Runtime.getRuntime() or "BALDERDASH". The
    conventional choice when there's really nothing better is to use
    the Class object for the class to which the method belongs, in
    this case `MessageDigest.class'.

    >> Perhaps the JavaDoc should explicitly say "getInstance()
    >>is safe to use in multi-threaded code," but I think we can
    >>probably take that for granted. If the static method operates
    >>on thread-unsafe objects, the method itself should take care
    >>of synchronizing appropriately. For example, a static factory
    >>method that maintains a cache of frequently-used objects may
    >>need to synchronize its own access to the cache, but the caller
    >>of the factory method shouldn't need to worry.

    >
    >
    > You are suggesting that we infer what the code is doing and that we can take
    > for granted that the API is doing what needs to be done to protect the code.
    > This is similar to a variety of posts that I've come across in a wide number
    > of forums that expressive a great deal of frustration that the
    > documentation is silent on so much of this. What you are saying is in line
    > with much that I've read but (acknowleding that I'm still new to dealing
    > with Threads in Java) this seems like a rather unsuitable way to go about
    > building software! You aren't expressing much concern that this is all
    > rather undocumented; can you help me understand why (if I am reading between
    > the lines correctly) this isn't an issue of much concern for you?


    What I'm saying -- although I don't think it's written down
    explicitly -- is that thread-safety is the "default assumption"
    for Java classes. BigInteger.valueOf(long) doesn't come right
    out and say that it's thread-safe, but I'm willing to assume it
    is even though it quite possibly manipulates a static cache.
    The practice in JavaDoc seems to be to highlight the things that
    are *not* thread-safe -- take a look at ArrayList, for example --
    rather than to note all the things that are. (I have to admit,
    though, that the opposite sometimes happens; see StringBuffer
    for an example.)

    Here's a final thought: `synchronized' does not in and of
    itself guarantee thread safety. We've all learned that Vector
    is synchronized, but the following is thread-unsafe anyhow:

    Vector v = getSomeVector();
    for (int i = 0; i < v.size(); ++i)
    System.out.println(v.get(i));

    See the problem? size() is safe and get() is safe, but that
    doesn't mean that the combined operation of size() followed by
    get() is safe. Just after this thread receives a value from
    size() a second thread could leap in and run clear() on the
    Vector before the first thread makes its call to get(), and
    you'd get an ArrayIndexOutOfBoundsException. You could fix
    the code this way:

    Vector v = getSomeVector();
    synchronized (v) {
    for (int i = 0; i < v.size(); ++i)
    System.out.println(v.get(i));
    }

    or if you didn't want to hold the lock for the entire loop you
    could write

    Vector v = getSomeVector();
    for (int i = 0; ; ++i) {
    synchronized (v) {
    if (i < v.size())
    System.out.println(v.get(i));
    else
    break;
    }
    }

    (although one might wonder whether this particular example
    makes a whole lot of sense).

    --
    Eric Sosman, Jun 22, 2005
    #6
  7. Al Koch

    John Currier Guest

    > public static final String appendTrailingBackslash(String sStr)
    > {
    > Object lockObject = new Integer(666);
    > StringBuffer sbStr = null;
    > synchronized(lockObject) {
    > sbStr = new StringBuffer(sStr);
    > }
    >
    > sbStr.append('\\');
    > return(sbStr.toString());
    > }


    It looks like you're trying to complicate things tremendously. There
    is nothing in this method that can be referenced by another thread
    other than possibly aStr, which is immutable. The method (actually
    more of a function) is thread safe without any form of synchronization.
    It can, of course, be replaced with String's "+" operator.

    John
    John Currier, Jun 23, 2005
    #7
  8. Al Koch

    Al Koch Guest

    Hi Eric,

    Again thanks for taking the time to write such an extensive reply. If
    others find this thread (no pun intended!) I'm sure they will benefit from
    all this!

    > `new' itself is safe for the same reason `+' is safe:
    > it's just an operator; it has no internal state of its own
    > that needs protection.


    OK, and you anticipated exactly what worried me about new. Yes, it's "just
    an operator" but it triggers a Ctor that does who knows what, but that's
    what you address next!


    > It's possible to write an unsafe constructor, but that's
    > a somewhat different matter. If a constructor is unsafe there's
    > really not much you can do about it; constructors are a lot like
    > static methods in this regard. However, I can think of only two
    > ways a constructor can be unsafe (perhaps the experts will chime
    > in with more):


    Good point; I'd hope that we can assume that any Ctor "thread errors" in
    J2SE/EE would have popped up by now so I'll stop worrying about that one!


    > >> There's no effective way to synchronize access to an
    > >>accessible static method -- you could synchronize on the
    > >>method's class or on any other agreed-upon object, but you'd
    > >>need to rely on all callers doing the synchronization, which
    > >>is hard to enforce.


    > What I'm saying -- although I don't think it's written down
    > explicitly -- is that thread-safety is the "default assumption"
    > for Java classes. BigInteger.valueOf(long) doesn't come right
    > out and say that it's thread-safe, but I'm willing to assume it
    > is even though it quite possibly manipulates a static cache.
    > The practice in JavaDoc seems to be to highlight the things that
    > are *not* thread-safe -- take a look at ArrayList, for example --
    > rather than to note all the things that are. (I have to admit,
    > though, that the opposite sometimes happens; see StringBuffer
    > for an example.)


    I'd like to accept your statement that "thread-safety is the "default
    assumption"" since that eliminates a lot of things to worry about but what
    worries me is that I've come across an overwhelming number of posts in all
    sorts of forums where the sentiment that was expressed was that we should
    assume that the API is *not* thread-safe unless it states that it is (such
    as StringBuffer does). Given so much conflicting opinion on this can you
    speculate on why Sun hasn't come out with some sort of definitive statement
    on this? Since thread safety is *essential* (at least in a multi-threaded
    environment which is so much of where Java is used such as servlets and Web
    Services apps), why would Sun allow such confusion to exist? If the API is
    thread-safe why not just say so? Their failure to make such a statement
    causes me to be concerned that it isn't.


    > Here's a final thought: `synchronized' does not in and of
    > itself guarantee thread safety. We've all learned that Vector
    > is synchronized, but the following is thread-unsafe anyhow:
    >
    > Vector v = getSomeVector();
    > for (int i = 0; i < v.size(); ++i)
    > System.out.println(v.get(i));
    >
    > See the problem? size() is safe and get() is safe, but that
    > doesn't mean that the combined operation of size() followed by
    > get() is safe. Just after this thread receives a value from
    > size() a second thread could leap in and run clear() on the
    > Vector before the first thread makes its call to get(), and
    > you'd get an ArrayIndexOutOfBoundsException. You could fix
    > the code this way:


    Yes, good point and by "thread-safe" I haven't meant that any place or way
    that a thread-safe API is used is therefore thread-safe. I meant that any
    Class or other "external" resources used within the API are synchronized.

    As a summary, let me restate what I am confused and concerned about. Here
    is my reasoning:

    1) There is much concern on the Web that the J2SE API is not thread-safe.
    If we choose to assume this...
    2) There is at least Class, call it UnsafeClass, that has at least one
    method, call it UnsafeAPI() that is not thread-safe, therefore ...
    3) There is either a Class variable in UnsafeClass, or UnsafeAPI() has an
    instance variable or there is some "external" resource such as a file,
    database connection, socket, etc. that is not synchronized by UnsafeAPI() .
    (If this were not true then UnsafeAPI() *would be* thread-safe!).

    We can ignore the case where it is an instance variable that is unprotected
    because if I have an instance of UnsafeClass I can just code
    synchronize("instance of UnsafeClass") {
    UnsafeAPI(
    }
    and all should be well.

    That leaves us with those cases where there is an unprotected Class variable
    or an unprotected external resource. I guess my question boils down to, how
    do I use UnsafeAPI() so that my code is thread-safe? Code like
    synchronize("instance of some Class other than UnsafeClass") {
    UnsafeAPI();
    }

    will not work because, while it will protect me from all threads that run
    thru my code where I've been sure to always synch on "instance of some Class
    other than UnsafeClass", this provides no protection from some other app
    running in the JVM from just making its own call to UnsafeAPI() while my
    thread is in there!

    Am I correct in concluding that as long as I need to use an "UnsafeAPI()"
    that there is simply no way to protect my code? I guess that is what you
    stated above when you said "There's no effective way to synchronize access
    to an accessible static method". As long as any other app running in the
    JVM can call "UnsafeAPI()", even if that programmer wanted to synch on
    something, it's a crapshoot as to whether or not he wrote
    synchronize("UnsafeClass.class") {
    UnsafeAPI(
    }

    The conclusion I just drew, IMO, puts us all in an unacceptable situation.
    As long as there is no way to assure synchrinization when using API's in the
    J2SE/EE it seems that all (threaded) code has a big vulnerability. That
    brings me back to your feeling that the API is thread-safe. If so, why in
    the world doesn't Sun take a position in this? Arggghhhh!

    Thanks much - this is a very valuable discussion,
    Al.
    Al Koch, Jun 23, 2005
    #8
  9. Al Koch

    Al Koch Guest

    Hi John,

    Thanks for the reply.

    > It looks like you're trying to complicate things tremendously. There
    > is nothing in this method that can be referenced by another thread
    > other than possibly aStr, which is immutable. The method (actually
    > more of a function) is thread safe without any form of synchronization.
    > It can, of course, be replaced with String's "+" operator.


    Yes, my example was a bit "contrived". The problem I have is that (since I
    am still new to threads in Java) I haven't yet come across an API that I can
    show is causing a problem, but please review the following and see if it
    makes sense.

    1) There is much concern on the Web that the J2SE/EE API is not thread-safe.
    In researching this I have come across a large number of threads (no pun
    intended) in a variety of forums and the great majority express the belief
    that the J2SE/EE API is not, unless it states otherwise, thread-safe. As
    far as I can tell, Sun has not stated that it is thread-safe and that in
    itself makes me suspect that it isn't. If we choose to assume that it is
    not, in general, thread-safe...
    2) There is at least one Class, call it UnsafeClass, that has at least one
    method, call it UnsafeAPI() that is not thread-safe, therefore ...
    3) There is either a Class variable in UnsafeClass, or UnsafeAPI() has an
    instance variable or there is some "external" resource such as a file,
    database connection, socket, etc. that is not synchronized by UnsafeAPI() .
    (If this were not true then UnsafeAPI() *would be* thread-safe!).

    We can ignore the case where it is an instance variable that is unprotected
    because if I have an instance of UnsafeClass I can just code
    synchronize("instance of UnsafeClass") {
    UnsafeAPI()
    }
    and all should be well.

    That leaves us with those cases where there is an unprotected Class variable
    or an unprotected external resource. I guess my question boils down to, how
    do I use UnsafeAPI() so that my code is thread-safe? Code like
    synchronize("instance of some Class other than UnsafeClass") {
    UnsafeAPI();
    }

    will not work because, while it will protect me from all threads that run
    thru my code where I've been sure to always synch on "instance of some Class
    other than UnsafeClass", this provides no protection from some other app
    running in the JVM from just making its own call to UnsafeAPI() while my
    thread is in there!

    Am I correct in concluding that as long as I need to use an "UnsafeAPI()"
    that there is simply no way to protect my code? As long as any other app
    running in the JVM can call "UnsafeAPI()", even if that programmer wanted to
    synch on something, it's a crapshoot as to whether or not he used what might
    be the "obvious" object to synch on as in
    synchronize("UnsafeClass.class") {
    UnsafeAPI(
    }


    The conclusion I just drew, IMO, puts us all in an unacceptable situation.
    As long as there is no way to assure synchronization when using API's in the
    J2SE/EE it seems that all (threaded) code has a big vulnerability. If this
    is not so, do you have any idea why in the world doesn't Sun take a position
    on this?

    Thanks much,
    Al.
    Al Koch, Jun 23, 2005
    #9
  10. Al Koch

    John Currier Guest

    The vast majority of "not thread safe" code is thread safe at the class
    level (i.e., it doesn't contain "unprotected" static members) but not
    at the instance level.

    Take SimpleDateFormat as an example. A single instance of
    SimpleDateFormat can't be used by multiple threads safely. The
    instance modifies its internal state during an invocation, so one
    thread can easily change another thread's results.

    The solution? Don't let multiple threads access that instance of the
    class. If you write a class that has a SimpleDateFormat instance
    variable and you want instances of your class to be thread safe then
    you'll need to wrap the formatter in a synchronized block.

    SimpleDateFormat *is* safe at the class level. That is, multiple
    threads can access their own instance of SimpleDateFormat without
    having to worry about somehow only allowing one thread into any
    instance of the class at a time.

    Hope this helps,
    John
    http://schemaspy.sourceforge.net
    John Currier, Jun 23, 2005
    #10
  11. Al Koch

    Guest

    In article <>,
    Al Koch <> wrote:
    >Hi Eric,
    >
    >Again thanks for taking the time to write such an extensive reply. If
    >others find this thread (no pun intended!) I'm sure they will benefit from
    >all this!


    Everyone following this discussion should be aware that there's a
    parallel (no pun intended) discussion with the same subject line going
    on in comp.java.lang.help. I'm going to try to cross-post this reply
    so people who follow both groups will get this ....

    Others are posting a lot of useful information. You might also find
    the following two links useful, if you haven't already come across
    them. (These were the most useful-seeming of the first few that
    popped up on a Google search for "not thread safe" and "Java".)

    http://www-128.ibm.com/developerworks/java/library/j-threads1.html

    http://www-106.ibm.com/developerworks/java/library/j-jtp09263.html

    Some classes are pretty explicit about thread-safety issues -- I checked
    ArrayList and found the following:

    Note that this implementation is not synchronized. If multiple threads
    access an ArrayList instance concurrently, and at least one of the
    threads modifies the list structurally, it must be synchronized
    externally. (A structural modification is any operation that adds or
    deletes one or more elements, or explicitly resizes the backing array;
    merely setting the value of an element is not a structural
    modification.) This is typically accomplished by synchronizing on some
    object that naturally encapsulates the list. If no such object exists,
    the list should be "wrapped" using the Collections.synchronizedList
    method. This is best done at creation time, to prevent accidental
    unsynchronized access to the list:
    List list = Collections.synchronizedList(new ArrayList(...));

    which seems pretty clear.

    But it's not clear that all classes are so well documented, and this
    is an interesting point I hadn't been aware of ....

    --
    | B. L. Massingill
    | ObDisclaimer: I don't speak for my employers; they return the favor.
    , Jun 23, 2005
    #11
  12. Al Koch

    Chris Head Guest

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Al Koch wrote:
    [snip]
    > Am I correct in concluding that as long as I need to use an "UnsafeAPI()"
    > that there is simply no way to protect my code? I guess that is what you
    > stated above when you said "There's no effective way to synchronize access
    > to an accessible static method". As long as any other app running in the
    > JVM can call "UnsafeAPI()", even if that programmer wanted to synch on
    > something, it's a crapshoot as to whether or not he wrote
    > synchronize("UnsafeClass.class") {
    > UnsafeAPI(
    > }

    [snip]


    Just to clarify:
    When he said UnsafeClass.class, he meant UnsafeClass.class, not
    "UnsafeClass.class".

    As in:

    synchronized(UnsafeClass.class) {
    UnsafeClass.UnsafeAPI();
    }

    This is actually a legal expression. It returns an object of type
    java.lang.Class representing UnsafeClass. THIS object is what
    synchronized static methods implicitly synchronize on. There is only one
    such object for each class per classloader.

    Also, I would suggest not synchronizing on strings because it's too easy
    to make a typo and the compiler won't catch it for you.

    Chris
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.1 (MingW32)

    iD8DBQFCuuZSgxSrXuMbw1YRAtSyAKCJFkRi3t/PtF4DINTmO84KZUBRXwCbBO43
    B0HnbPtNvd5bLBOJfvrUM94=
    =p1Eq
    -----END PGP SIGNATURE-----
    Chris Head, Jun 23, 2005
    #12
  13. Al Koch

    Eric Sosman Guest

    Al Koch wrote:
    > [...] Given so much conflicting opinion on this can you
    > speculate on why Sun hasn't come out with some sort of definitive statement
    > on this?


    Just in case you're reading more into my E-mail address
    than is actually there: I do not speak for Sun Microsystems,
    and I *definitely* do not speculate for Sun Microsystems!
    I speak and speculate for myself; if you need "authoritative"
    answers I'm not the source. Clear?

    > As a summary, let me restate what I am confused and concerned about. Here
    > is my reasoning:
    >
    > 1) There is much concern on the Web that the J2SE API is not thread-safe.


    Well, that's just a special case of "There is much concern
    on the Web that X," where X can be almost anything.

    > If we choose to assume this...
    > 2) There is at least Class, call it UnsafeClass, that has at least one
    > method, call it UnsafeAPI() that is not thread-safe, therefore ...
    > 3) There is either a Class variable in UnsafeClass, or UnsafeAPI() has an
    > instance variable or there is some "external" resource such as a file,
    > database connection, socket, etc. that is not synchronized by UnsafeAPI() .
    > (If this were not true then UnsafeAPI() *would be* thread-safe!).


    As I tried to illustrate in my previous post, "thread-safe"
    is not entirely cut-and-dried. It is possible to use a "thread-
    safe" interface in unsafe ways. Even StringBuffer can be used
    unsafely (the example I gave for Vector shows one way).

    > We can ignore the case where it is an instance variable that is unprotected
    > because if I have an instance of UnsafeClass I can just code
    > synchronize("instance of UnsafeClass") {
    > UnsafeAPI(
    > }
    > and all should be well.


    No, not if someone other than you fails to follow this
    discipline. It's not enough that *you* code this way; you've
    got to get *everyone* to code this way.

    One approach is to wrap the suspect object in a class of
    your own that synchronizes and then delegates:

    class ArmoredUnsafeClass {
    private UnsafeClass obj = new UnsafeClass();
    synchronized void UnsafeAPI() {
    obj.UnsafeAPI();
    }
    }

    See Collections.synchronizedCollection() for an example of a
    slightly different way to get the same effect.

    > That leaves us with those cases where there is an unprotected Class variable
    > or an unprotected external resource. I guess my question boils down to, how
    > do I use UnsafeAPI() so that my code is thread-safe? Code like
    > synchronize("instance of some Class other than UnsafeClass") {
    > UnsafeAPI();
    > }
    >
    > will not work because, while it will protect me from all threads that run
    > thru my code where I've been sure to always synch on "instance of some Class
    > other than UnsafeClass", this provides no protection from some other app
    > running in the JVM from just making its own call to UnsafeAPI() while my
    > thread is in there!


    Well, if the "un-safety" involves only instance variables,
    you can use ArmoredUnsafeClass instead of UnsafeClass. Other
    code may be using UnsafeClass directly, but as long as it can
    never get hold of a reference to one of your "armored" objects,
    it can't bother you or be bothered by you.

    If the "un-safety" involves (ab)use of a shared resource --
    a network connection, say -- then you've got a bigger problem.
    If UnsafeAPI() carries on an extended dialogue across a socket,
    exchanging several messages with the peer, then two simultaneous
    UnsafeAPI() invocations will probably garble both conversations.
    You could synchronize on any convenient and agreed-upon object
    (like UnsafeClass.class or the socket), but if there are chunks
    of code not under your control you can't be sure you've found
    all the bad spots or that somebody else won't introduce a new one.
    But in a case like this I'd argue that either UnsafeClass is
    broken (its implementor didn't think about thread safety) or that
    it's being misused (there's some "natural" reason for having only
    one thread use the API, and the application shouldn't be trying
    to use it concurrently in the first place).

    > The conclusion I just drew, IMO, puts us all in an unacceptable situation.
    > As long as there is no way to assure synchrinization when using API's in the
    > J2SE/EE it seems that all (threaded) code has a big vulnerability. That
    > brings me back to your feeling that the API is thread-safe. If so, why in
    > the world doesn't Sun take a position in this? Arggghhhh!


    As mentioned above, I don't speculate for Sun. I *do* think
    you're worrying far too much; the existence and success of big
    bundles of multi-threaded Java applications suggests that the
    problems are not as severe as you seem to believe. Are you, by
    any chance, old enough to remember Skylab helmets?

    --
    Eric Sosman, Jun 23, 2005
    #13
  14. Al Koch

    Al Koch Guest

    Hi BL,

    > Others are posting a lot of useful information. You might also find
    > the following two links useful, if you haven't already come across
    > them. (These were the most useful-seeming of the first few that
    > popped up on a Google search for "not thread safe" and "Java".)
    >
    > http://www-128.ibm.com/developerworks/java/library/j-threads1.html
    >
    > http://www-106.ibm.com/developerworks/java/library/j-jtp09263.html


    These are some good links - thanks for posting them!


    > Some classes are pretty explicit about thread-safety issues -- I checked
    > ArrayList and found the following:

    ,,,
    > But it's not clear that all classes are so well documented, and this
    > is an interesting point I hadn't been aware of ....


    Yes, that's really my concern. This apears to be a difficulr area because
    it seems that in the absence of Sun (or whoever is the JVM vendor) stating
    that their implementation is "thread-safe except for ... " or "not
    thread-safe except for ..." we are left with a really big burden, e.g., each
    of us has to review the source for the API implementation, which is simply
    not practical! Bloch's "Five Degrees..." would really be helpful here!

    Thanks.

    Al,
    Al Koch, Jun 23, 2005
    #14
  15. Al Koch

    Al Koch Guest

    Hi Chris,

    > Just to clarify:
    > When he said UnsafeClass.class, he meant UnsafeClass.class, not
    > "UnsafeClass.class".
    >
    > As in:
    >
    > synchronized(UnsafeClass.class) {
    > UnsafeClass.UnsafeAPI();
    > }
    >
    > This is actually a legal expression. It returns an object of type
    > java.lang.Class representing UnsafeClass. THIS object is what
    > synchronized static methods implicitly synchronize on. There is only one
    > such object for each class per classloader.
    >
    > Also, I would suggest not synchronizing on strings because it's too easy
    > to make a typo and the compiler won't catch it for you.


    You are right. I had meant
    UnsafeClass.class
    not a quoted string. I had been using quoted strings to reference "logical"
    objects described by the string and got carried away. Thanks for keeping
    the readers on the right path!

    Al,
    Al Koch, Jun 23, 2005
    #15
  16. Al Koch

    Al Koch Guest

    Hi Eric,

    > As mentioned above, I don't speculate for Sun. I *do* think
    > you're worrying far too much; the existence and success of big
    > bundles of multi-threaded Java applications suggests that the
    > problems are not as severe as you seem to believe. Are you, by
    > any chance, old enough to remember Skylab helmets?


    Well, would you believe that I never looked at your email address (duh) so
    when I asked if you couild speculate on why Sun wasn't (as far as I can
    tell) saying much to try and clarify things it wasn't because I knew you
    worked there; I thought I was just asking someone who appeared to be
    credible!

    After about a week of throught and research (a big part of it informed by
    your posts) I now have a much better understanding of the issues. It looks
    like there's a reasoanable soultion to the various issues I've raised except
    for use of a J2SE/EE method that manipulates Class data or some "external
    resource". I'm sure it's been obvious to you all along but the fog is now
    clearing and I see that this is the area of potential vulnerability. Since
    we are talking about a J2SE/EE method I have no control over who else might
    be using it (in the same JVM) and how they use it so "all bets are off".
    But your final comments about being overly concerned are perhaps the most
    useful of all. As I said when I started the thread I'm new to threading for
    Java so I did not yet have any calibration for the size of the problem. You
    have been a big help in my development of the proper sense of concern here.
    I'll go with your suggestion that "the sky ain't falling!". (However, it's
    too bad that in a few more years we'll have to go get some "Hubble
    helmets"!)

    Thanks for all your help. It has been a pleasure communicating with you!

    Al,
    Al Koch, Jun 23, 2005
    #16
  17. Al Koch

    Al Koch Guest

    Hi John,

    Thanks for your reply.

    "John Currier" <> wrote in message
    news:...
    > The vast majority of "not thread safe" code is thread safe at the class
    > level (i.e., it doesn't contain "unprotected" static members) but not
    > at the instance level.
    >
    > Take SimpleDateFormat as an example. A single instance of

    ,,,

    The J2SE/EE docs say something about SimpleDateFormat;s synchronization.
    One of the problems I'm having is the many (maybe most?) classes in the
    J2SE/EE docs don't appear to say anything one way or another. In general
    then, how do you deternine the degree of thread safety a class's method's
    have?

    Al,
    Al Koch, Jun 23, 2005
    #17
  18. Al Koch

    John Currier Guest

    The note doesn't mention that the synchronized collection wrappers'
    Iterators aren't thread-safe...you've got to synchronize on the wrapper
    if you need thread-safe access to the collection via an iterator.

    John
    http://schemaspy.sourceforge.net
    John Currier, Jun 23, 2005
    #18
  19. Al Koch

    Dale King Guest

    Al Koch wrote:
    > Hello,
    >
    > I am writing a Java servlet and am new to coding for thread synchronization.
    > I suspect that there must be an "obvious" solution to the following problem
    > but after sevearl days of research I can't find it!
    >
    > It is my understanding that, in general, the J2SE 1.4 API is *not*
    > thread-safe. There are some APIs where the Sun documentation states that a
    > Class's methods are thread-safe (such as StringBuffer) but in general, most
    > of the text and web search references I have found have stated that the API
    > in general is not thread-safe. That means that there must be at least one
    > (and it's probably most) API that is not thread-safe and let me just call
    > such an unsafe method "UnsafeAPI()". My question is, how do I use
    > UnsafeAPI() and write code to make my code thread-safe?


    You seem to have a lot to learn about what it really means to be "thread
    safe". Yes most of the API is not thread safe in that it is not safe for
    multiple threads to be calling methods on an instance without some sort
    of synchronization mechanism. That is not a bad thing.

    Thread safety does not begin and end with the Java API. Even if every
    method in the Java API were synchronized that would not in and of itself
    guarantee much of anything about the thread safety of any program that
    used those API's. Thread safety involves how an API is used as well.

    Consider if I had a class that maintained its state using a Vector and a
    Hashtable. Both of those classes are thread safe in that you can make
    calls on an instance from multiple threads and the internal state of the
    Hashtable or Vector will be consistent. But in my class that uses them
    if I add an item it needs to be added to the Hashtable and Vector. If I
    don't do synchronization within my class then I can still end up with an
    inconsistent state between the Hashtable and Vector.

    Since most thread safety issues involve big picture issues like this it
    is rather pointless (and quite harmful from a performance standpoint) to
    have the low level API's try to be thread safe (and giving users a false
    sense of security). Most of the time an API will only be accessed from
    one thread any way. They therefore elect to put the burden on the user
    to determine the best way to make it thread safe, but provide some
    optional low level thread safety on the very simple classes like the
    collection classes and StringBuilder vs. StringBuffer.
    --
    Dale King
    Dale King, Jun 24, 2005
    #19
  20. Al Koch

    Dale King Guest

    Eric Sosman wrote:
    >
    > `new' itself is safe for the same reason `+' is safe:
    > it's just an operator; it has no internal state of its own
    > that needs protection.
    >
    > It's possible to write an unsafe constructor, but that's
    > a somewhat different matter. If a constructor is unsafe there's
    > really not much you can do about it; constructors are a lot like
    > static methods in this regard. However, I can think of only two
    > ways a constructor can be unsafe (perhaps the experts will chime
    > in with more):
    >
    > - While building the new object, the constructor could
    > manipulate some other object that could be accessible
    > to another thread. For example, a constructor that
    > maintained a "registry" of constructed instances might
    > manipulate the registry without synchronizing. I'd
    > consider this a bug in the constructor.
    >
    > - The constructor could put a reference to the new object
    > someplace where another thread could find it, and then
    > proceed to manipulate the new object without synchronizing.
    > Again, I'd consider this a constructor bug.


    There has been discussion in this group and on the web in reference to
    "double-checked locking" that a VM can set a variable to reference the
    newly created object before the objects constructor has actually
    completed, which would allow another thread to access an object before
    its construction is complete.

    Things get really complicated when you start talking about mulitple
    processors and the memory model.

    See for example, the following:
    http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

    --
    Dale King
    Dale King, Jun 24, 2005
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jamie Burns
    Replies:
    31
    Views:
    3,461
    Keith H Duggar
    Feb 1, 2004
  2. Timothy Madden
    Replies:
    1
    Views:
    347
    Howard
    Nov 19, 2004
  3. Gabriel Rossetti
    Replies:
    0
    Views:
    1,293
    Gabriel Rossetti
    Aug 29, 2008
  4. Mats Olsson
    Replies:
    9
    Views:
    360
    Just1Coder
    Sep 14, 2004
  5. John Nagle
    Replies:
    5
    Views:
    447
    John Nagle
    Mar 12, 2012
Loading...

Share This Page