Deadlock Analysis in NetBeans 8

Lock contention profiling is very important in multi-core environments. Lock contention occurs when a thread tries to acquire a lock while another thread is holding it, forcing it to wait. Lock contentions kill your possible performance gain in using multiple cores in parallel since you are sequentialising work by using locks. In a worst case scenario, only one thread will run. In NetBeans 8, the NetBeans Profiler has new support for displaying detailed information about lock contention, i.e., the performance bottleneck, helping you to identify the responsible thread.

As an example, let's take the handy Deadlock sample code from the Java Tutorial and look at the tools in NetBeans IDE for identifying and analyzing the code. The description of the deadlock is nice:

Alphonse and Gaston are friends, and great believers in courtesy. A strict rule of courtesy is that when you bow to a friend, you must remain bowed until your friend has a chance to return the bow. Unfortunately, this rule does not account for the possibility that two friends might bow to each other at the same time.

To help identify who bowed first or, at least, the order in which bowing took place, right-click the file and choose "Profile File". In the Profile Task Manager, make the choices below:

When you have clicked Run, the Threads window shows the two threads are blocked, i.e., the red "Monitor" lines tell you that the related threads are blocked while trying to enter a synchronized method or block:

But which thread is holding the lock? Which one is blocked by the other? The above visualization does not answer these questions.

New in NetBeans 8 is that you can analyze the deadlock in the new Lock Contention window to determine which of the threads is responsible for the lock:

Here is the code that simulates the lock, very slightly tweaked at the end, where I use "setName" on the threads, so that it's even easier to analyze the threads in the relevant NetBeans tools. Also, I converted the anonymous inner Runnables to lambda expressions.

package org.demo;
public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                    + " has bowed to me!%n",
                    this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                    + " has bowed back to me!%n",
                    this.name, bower.getName());
        }
    }
    public static void main(String[] args) {
        final Friend alphonse
                = new Friend("Alphonse");
        final Friend gaston
                = new Friend("Gaston");
        Thread t1 = new Thread(() -> {
            alphonse.bow(gaston);
        });
        t1.setName("Alphonse bows to Gaston");
        t1.start();
        Thread t2 = new Thread(() -> {
            gaston.bow(alphonse);
        });
        t2.setName("Gaston bows to Alphonse");
        t2.start();
    }
}

In the above code, it's extremely likely that both threads will block when they attempt to invoke bowBack. Neither block will ever end, because each thread is waiting for the other to exit bow.

Note: As you can see, it really helps to use "Thread.setName", everywhere, wherever you're creating a Thread in your code, since the tools in the IDE become a lot more meaningful when you've defined the name of the thread because otherwise the Profiler will be forced to use thread names like "thread-5" and "thread-6", i.e., based on the order of the threads, which is kind of meaningless. (Normally, except in a simple demo scenario like the above, you're not starting the threads in the same class, so you have no idea at all what "thread-5" and "thread-6" mean because you don't know the order in which the threads were started.) Slightly more compact:

Thread t1 = new Thread(() -> {
    alphonse.bow(gaston);
},"Alphonse bows to Gaston");
t1.start();
Thread t2 = new Thread(() -> {
    gaston.bow(alphonse);
},"Gaston bows to Alphonse");
t2.start();
Comments:

Meh, a simple kill -3 will do the same job. And faster.

Posted by alex on June 02, 2014 at 09:55 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« March 2015
SunMonTueWedThuFriSat
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    
       
Today