Page 1 of 1

About Question enthuware.ocpjp.v7.2.1343 :

Posted: Wed Aug 06, 2014 12:10 pm
by bluster
Piece of trivia.. It will not deadlock easily.

I added

Code: Select all

static AtomicInteger counter = new AtomicInteger();
to the class, then

Code: Select all

System.out.println("Counter from one: " + counter.getAndIncrement());
and

Code: Select all

System.out.println("Counter from two: " + counter.getAndIncrement());
after the respective lines printing the StringBuffers.

Finally I wrapped the entire main inside a while (true) infinite loop. The purpose was to see how many interactions it would take until the deadlock. Unfortunately every run blew up from lack of memory for new threads, and only for that reason.

Below is pasted the end of one run, where over 36,000 interactions went by until the JVM croaked out of memory, without the satisfaction of a deadlock. If someone can see a mistake in the code, please let me know, I wanted to see the deadlocking fireworks. Thanks!
Counter from one: 36860
Counter from two : 36861
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Wed Aug 06, 2014 8:12 pm
by admin
Try this code:

Code: Select all

public class DeadlockTest {

    static StringBuffer sb1 = new StringBuffer();
    static StringBuffer sb2 = new StringBuffer();

    public static void main(String[] args) throws Exception {
        int i = 0;
        while (true) {
            System.out.println("Starting iteration " + i++);
            Thread t1 = new Thread(
                    new Runnable() {
                public void run() {
                    synchronized (sb1) {
                        sb1.append("X");
                        try {
                            Thread.sleep((int) Math.random() * 1000);
                        } catch (Exception e) {
                        }
                        synchronized (sb2) {
                            sb2.append("Y");
                        }
                    }
                    System.out.println(sb1);
                }
            });
            t1.start();
            Thread t2 = new Thread(
                    new Runnable() {
                public void run() {
                    synchronized (sb2) {
                        sb2.append("Y");
                        try {
                            Thread.sleep((int) Math.random() * 1000);
                        } catch (Exception e) {
                        }
                        synchronized (sb1) {
                            sb1.append("X");
                        }
                    }
                    System.out.println(sb2);
                }
            });
            t2.start();
            t1.join();
            t2.join();
        }

    }
}
HTH,
Paul.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Mon Feb 09, 2015 9:36 pm
by ewebxml
For both thread instances you have a synchronized block
nested within a synchronized block .

Question 1: In practice, is this unconventional
OR
would this be looked upon negatively in practice?


Question 2: Can one generalize if nested synchronized blocks will always
lead to a deadlock?

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Tue Feb 10, 2015 12:39 am
by admin
1. No, it is not unconventional. If you need to lock multiple resources, this is the way to do it. What is looked at negatively is if you acquire multiple resources in a different order(i.e. lock a and b in one place, and lock b and a in another). The correct way is to lock them in the same order (if you have to lock them from different classes).

2. If you lock them in a different order, you will run into a deadlock. If you lock them in the same order, there will never be a deadlock.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Wed Feb 06, 2019 3:33 pm
by abutalib
I don't understand.

By locking a static field sb1, doesn't that automatically lock (TestClass.class)? Therefore, the second thread will never be able to acquire the lock on sb2 because (TestClass.class) is already locked?

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Wed Feb 06, 2019 6:57 pm
by admin
>By locking a static field sb1, doesn't that automatically lock (TestClass.class)?

No, where did you read that?

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Thu Feb 07, 2019 3:20 am
by abutalib
Because if you synchronize a static method, it synchronizes the TestClass.class.

So then my question, if I lock a field (static or instance) it locks that field only and nothing else? The instance holding will not be locked as well?

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Thu Feb 07, 2019 3:41 am
by admin
abutalib wrote:
Thu Feb 07, 2019 3:20 am
Because if you synchronize a static method, it synchronizes the TestClass.class.
Yes, just like an instance method uses the lock on the "this" object, the static method uses the lock of the Class object of that class.

But when you synchronize directly on an object (i.e. synchronized( anyObjectReference) ) then the lock associated with that object is used. Whether that reference is a static member or an instance member of a class is immaterial to the object pointed to by that reference.
So then my question, if I lock a field (static or instance) it locks that field only and nothing else? The instance holding will not be locked as well?
No. You need to understand that a lock is always associated with an object, but it is not the object that are locked. It is a piece of code that is locked from being executed by other threads. Instead of thinking that you are locking an object, think of it like you are using the lock associated with an object to lock a block of statements.

Go through a good book on this topic to make sure you understand this correctly because it is not possible to explain this topic fully in a forum post.

HTH,
Paul.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Thu Feb 07, 2019 4:02 am
by abutalib
The second quote was a bad phrasing on my side. I think I got it.

When we synchronize on an object, the thread that acquires the lock first will execute the block of code uninterrupted by other threads as long until it has released the lock.

As for these multiple locks, they are usually done with the help of private fields.

Am I correct?

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Thu Feb 07, 2019 4:33 am
by admin
abutalib wrote:
Thu Feb 07, 2019 4:02 am
As for these multiple locks, they are usually done with the help of private fields.

Am I correct?
Can't really say. Difficult to generalize like that.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Sat Aug 08, 2020 1:39 pm
by Javier
Hi Paul!
is it correct to say that the TestClass holds an anonymous Thread class and the Thread class implements in its consctructor the Runnable interface?
So this code is like if we write:
TestClass extends Thread, and Thread implements Runnable?
Thank you in advance.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Sun Aug 09, 2020 12:58 am
by admin
Yes, you can think of it that way. You would create two instance of TestClass instead of the anonymous classes.
But I am not sure what you mean by this sentence, " Thread class implements in its consctructor the Runnable interface". Thread class does implement Runnable but what do you mean by "in its constructor"?

Please post code to show what you mean to avoid any confusion.

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Sun Aug 09, 2020 10:32 am
by Javier

Code: Select all

 public static void main(String[] args){
new Thread 
[u]([i]//here is the beginning of the constructor of Thread Class [/i] 
[/u]         new Runnable()          
{             public void run()             
{                 synchronized(sb1)                 
{                     sb1.append("X");                     
                      synchronized(sb2)                    
 {                       sb2.append("Y");
                     }                 
}                 System.out.println(sb1);            
 }          
}       
[u][i]//here is the end of the constructor of the Thread Class
[/u][/i]).start();
That is why I said "the Runnable interface is implemented in the constructor of the Thread Class".

Re: About Question enthuware.ocpjp.v7.2.1343 :

Posted: Sun Aug 09, 2020 11:23 am
by admin
OK, I see now what you mean.