0

System.out.println("hey got it...."); never executed in my program

I can understand its because of synchronized keyword but what is actually happening with that.

TestJoin class called from CFG class and the problem is in this class

 class TestJoin implements Runnable{

    public String x;

    TestJoin(String x){
        this.x= x;

    }

    public void testJoin() {
        System.out.println("b4"+x);
        synchronized(x) {
            System.out.println(x);
            ThreadJoining t1 = new ThreadJoining("2");

            // thread t1 starts
            t1.start();
            System.out.println("you fool");
            try{
                System.out.println(
                    "Current Thread: "+ 
                    Thread.currentThread().getName()
                );
                t1.join();
               //never this line is executed
               System.out.println("hey got it....");
            }catch(Exception ex){
                System.out.println(
                       "Exception has " +
                       "been caught" + ex
                );
            }
        }
    }

    @Override
    public void run() {
            testJoin();
    }
}

Simply creating another thread its called from TestJoin class

class ThreadJoining extends Thread{
        String c;
        ThreadJoining(String co){
            c=co;
        }
        @Override
        public void run()
        {
            synchronized(c) {
                for (int i = 0; i < 2; i++){
                try{
                    Thread.sleep(500);
                    System.out.println(
                             "Current Thread: " +
                             Thread.currentThread().getName()
                    );
                }catch(Exception ex){
                    System.out.println(
                                "Exception has" +
                                " been caught" + ex
                    );
                }
                System.out.println(i);
            }
        }
    }
}

Main class execution starts from here

public class GFG{
    public static void main (String[] args){

        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                System.out.println("Bye Bye");
            }
        });
        new Thread(new TestJoin("1")).start();
        new Thread(new TestJoin("1")).start();
        new Thread(new TestJoin("2")).start();
        new Thread(new TestJoin("3")).start();

     }
}

output for the above execution

b41
1
b43
3
b42
2
b41
you fool
Current Thread: Thread-4
you fool
Current Thread: Thread-1
you fool
Current Thread: Thread-3

Second Edit:

The above issue is only if I synchronize with string or singleton object, if I use a new object Its perfectly file

Example, with normal object synchronization

public class GFG{
        public static void main (String[] args){

            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    System.out.println("Bye Bye");
                }
            });
           Sample s =  new Sample();
           new Thread(new TestJoin(s)).start();
           new Thread(new TestJoin(s)).start();
           new Thread(new TestJoin(new Sample())).start();
           new Thread(new TestJoin(new Sample())).start();

        }
    }

public class TestJoin implements Runnable{

    public Sample x;
    TestJoin(Sample x){
        this.x= x;

    }

    public void testJoin() {
        System.out.println("b4"+x);
        synchronized(x) {
            System.out.println(x);
    ThreadJoining t1 = new ThreadJoining("2");

    // thread t1 starts
    t1.start();
    System.out.println("you fool");
    try
    {
        System.out.println("Current Thread: "
              + Thread.currentThread().getName());
        t1.join();
        System.out.println("hey got it....");
    }

    catch(Exception ex)
    {
        System.out.println("Exception has " +
                            "been caught" + ex);
    }
        }
    }

    @Override
    public void run() {
            testJoin();
    }
}

class ThreadJoining extends Thread{
    String c;
    ThreadJoining(String co){
        c=co;
    }

    @Override
    public void run(){
        synchronized(c) {
            for (int i = 0; i < 2; i++){
                try{
                    Thread.sleep(500);
                    System.out.println(
                        "Current Thread: " +
                        Thread.currentThread().getName()
                    );
                }catch(Exception ex){
                    System.out.println(
                        "Exception has" +
                        " been caught" + ex
                    );
                }
                System.out.println(i);
            }
        }
    }
}

public class Sample {

}

Output

b4Sample@a5c4778
b4Sample@27efa2ad
b4Sample@a5c4778
b4Sample@27507837
Sample@27507837
Sample@27efa2ad
Sample@a5c4778
you fool
you fool
Current Thread: Thread-4
you fool
Current Thread: Thread-3
Current Thread: Thread-1
Current Thread: Thread-6
0
Current Thread: Thread-6
1
hey got it....
Current Thread: Thread-5
0
Current Thread: Thread-5
1
hey got it....
Current Thread: Thread-7
0
Current Thread: Thread-7
1
hey got it....
Sample@a5c4778
you fool
Current Thread: Thread-2
Current Thread: Thread-8
0
Current Thread: Thread-8
1
hey got it....
Bye Bye
hellow
  • 12,430
  • 7
  • 56
  • 79
Ramu
  • 11
  • 5
  • 4
    Not a good idea to synchronize on `String` – xingbin Aug 15 '18 at 04:14
  • 1
    That's an understatement. – shmosel Aug 15 '18 at 04:16
  • But even if I synchronize with singleton object same issue is happening but when I create a new object its working fine. – Ramu Aug 15 '18 at 04:22
  • 1
    Looks like a deadlock to me. You have one of your TestJoin1 holding the lock while the other one is still waiting on its ThreadJoining to complete (which also needs the same lock at the top of its `run`). Or something like that. Try a `kill -QUIT ` to see the thread dump and which locks they are holding and waiting for. – Thilo Aug 15 '18 at 04:34
  • See https://stackoverflow.com/questions/133988/synchronizing-on-string-objects-in-java – GhostCat Aug 15 '18 at 10:48

1 Answers1

3

It's because String constants are interned, so where you synchronise on "2" in ThreadJoining and TestJoin, you're actually locking on the same object.

This leads to a deadlock when new TestJoin("2") locks on "2" and then waits for new ThreadJoining("2") to finish (which will never happen, because it can't get the lock on "2").

teppic
  • 7,051
  • 1
  • 29
  • 35