views:

68

answers:

4

I believed the String pool abandoned local Strings when their methods completed

Yet:

public class TestPool implements Runnable{

    /**
     * @param args the command line arguments
     */
    public void run() {
        String str= "hello";
        synchronized(str){

            try {
                System.out.print(Thread.currentThread().getName());
                Thread.sleep(500);
                System.out.print(Thread.currentThread().getName());
            }

            catch(InterruptedException e){

            }

        }
         }
        public static void main(String []args){
            new Thread(new TestPool(),"A").start();
            new Thread(new TestPool(),"B").start();
        }
    }

According to the whizlabs' guide, this code is correcly synchronizing its threads based on a local String. The output will always be AABB or BBAA. Why? Why does the str String outlive its local declaration?

+2  A: 

str is a local variable whose scope is limited to the run() method it's defined in. For different Threads, there should be different strs.

However, both of those different local strs point at the String "hello", which, as a compile-time constant, is interned. That is, a single instance of a String with that content is produced in a pool, and anything which points to the same run of characters will be pointed at that same object.

It's as if you had created a static instance of such a String.

Carl Smotricz
+1 for "(updating) - be right back!"?
Michael Myers
I should write that more often :) Hope my final text also merits the vote.
Carl Smotricz
The reference is a local variable, but the String it points to isn't. See what happens when you change the declaration to String str = new ("hello");
omgzor
That's what I said. Looks like you got it! :)
Carl Smotricz
+3  A: 

Yes, str is only a local variable, but it is pointing into the string pool; on two successive invocations of the method, str will be pointing to the same place in the pool, so you are still synchronizing on the same object.

If your code was

String str = new String("hello");

then you would indeed be synchronizing on a local object.

Michael Myers
+3  A: 

Because both local declarations of str point to the same interned String literal "hello". Interned strings are constants and maintained in a pool. They do not have a typical lifecycle and thus do not get garbage collected when there aren't anymore references.

This would not be the case if the declaration was

String str = new String("hello");
Robin
A: 

It's not that the string pool is taking local variables, it's that "hello" is only stored once and reused (since Strings are immutable).

Try this inside your synchronized block, both threads will print the same value, indicating you have the same object.

System.out.println( str.hashCode() );
karoberts
I think you're contradicting yourself. The "hello" String is stored in the String pool. There's nowhere else for it to be stored.
omgzor
hashCode is not reliable for testing for same Object. ... 1) different Strings can result in the same hashCode ("10" and "0O") ... 2) 2 distinct Strings (a != b) with the same content (a.equals(b)) must return the same hashCode
Carlos Heuberger