DEV Community

Cover image for Java Concurrency Tutorial - How to avoid deadlock in Java?
javinpaul
javinpaul

Posted on

Java Concurrency Tutorial - How to avoid deadlock in Java?

Disclosure: This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided in this article.

Hello guys, do you want to learn how to avoid deadlock while writing concurrent programs, especially in Java? Writing correct concurrent applications is never easy as you have to deal with several concurrency issues like race conditions, livelock, deadlock, memory interference, etc.

In this article, I'll tell you how to avoid deadlock while writing a concurrent program as an interview question discussion. Since I am a Java developer, I'll explain the concept and implementation in Java but the technique I'll share with you is valid for all kinds of programming languages like C++ or C#, etc.

The question of avoiding deadlock is one of the popular Java interview questions, with multi-threading being asked mostly at a senior level interview with lots of follow up questions.

Even though the question looks very basic, most of the Java developers get stuck once you start going deeper.

So, what is a deadlock? The answer is simple --- when two or more threads are waiting for each other to release the resource they need (lock) and get stuck for infinite time, the situation is called deadlock.

It will only happen in the case of multitasking or multi-threading because that's where multiple threads come into the picture.

1. How to detect Deadlock in Java Programs?

Though this could have many answers, first, I would look at the code to see if a nested synchronized block is calling a synchronized method from another or if it is trying to get a lock on a different object.

If that is the case, there is a good chance of deadlock, if the developer is not careful.

Another way to determine deadlock risks is when you actually get dead-locked while running the application.

If this happens, try to take a thread dump, in Linux, you can do this by the command "kill -3." This will print the status of all threads in an application log file, and you can see which thread is locked on which object.

You can analyze that thread dump by using tools like fastthread.io, which allows you to upload your thread dump and analyze it.

Another way is to use the jConsole/VisualVM. It will show you exactly which threads are getting locked and on which object.

If you are interested in learning about troubleshooting tools and the process of analyzing your thread dump, I suggest you take a look at this Analyzing Java Thread Dumps course on Pluralsight by Uriah Levy.

This is an advanced practice course to learn more about Java thread dump and familiarize you with other popular advanced troubleshooting tools.

Btw, you would need a Pluralsight membership to get access to this course, which costs around $29 per month or $299 annually (14% discount).

If you don't have Pluralsight membership, I encourage you to get one because it allows you to access their 5000+ online courses on all latest topics like front-end and back-end development, machine learning, etc.

It also includes interactive quizzes, exercises, and the latest certification material. It's more like Netflix for Software Developers and Since learning is an important part of our job, Pluralsight membership is a great way to stay ahead of your competition.

They also provide a 10-day free trial without any commitment, which is a great way to not just access this course for free but also to check the quality of courses before joining Pluralsight.

2. Write a Java Program That Will Result in Deadlock

After you answer the earlier question, they may ask you how to write code that will result in a deadlock in Java.

Here is one way of doing it:

Multithreading and Parallel Computing in Java

If method1() and method2() are both called by two or more threads, there is a good chance of deadlock, because if Thread 1 acquires a lock on a String object while executing method1() and Thread 2 acquires a lock on the Integer object while executing method2(), both will be waiting for each other to release a lock on the Integer and String to proceed further, which will never work.

This diagram effectively demonstrates our program, where one thread holds a lock on one object and is waiting for the other object to lock, which is held by the other thread.

You can see that Thread 1 wants the lock on Object 2, which is held by Thread 2, and Thread 2 wants a lock on Object 1, which is held by Thread 1.

Since no thread is willing to give up, there is a deadlock and the Java program is stuck. This condition is also known as "Circular Wait with No Preemption".

The idea is that you should know the right way to use common concurrent patterns, and if you are not familiar with them then Applying Concurrency and Multi-threading to Common Java Patterns by Jose Paumard is a good starting point to learn.

3. How to Avoid Deadlock in Java

Now, the interviewer comes to the final part and one of the most important questions, in my opinion: How do you fix a deadlock in code?

If you have looked at the above code carefully, then you may have figured out that the real reason for the deadlock is not multiple threads, but it is the way that they are requesting a lock.

If you provide an ordered access, then the problem will be resolved.

Here is my fixed version, which avoids deadlock by using a circular wait with no preemption. This is one of the four conditions needed for deadlock

Now, there would not be any deadlock, because both methods are accessing a lock on the Integer and String class literal in the same order.

So, if Thread A acquires a lock on the Integer object, thread B will not proceed until thread A releases the Integer lock.

This is done in the same way Thread A will not be blocked, even if Thread B holds a String lock, because, now, Thread B will not expect thread A to release an Integer lock to proceed any further.

That's all about how to avoid a deadlock while writing concurrent programs. As I have said that even the discussion and example in Java, the technique I have shared, ordered access to a shared resource is language independent and applicable everywhere.

Formally this is known as breaking the Circular Wait with No Preemption condition required for deadlock but I just call it ordered access of the shared resource.

If you want to learn more about Concurrency, Multithreading, and Concurrent programming in general, here are some useful resources.:

Further Learning
Multithreading and Parallel Computing in Java
Java Concurrency in Practice --- The Book
Applying Concurrency and Multi-threading to Common Java Patterns
Java Concurrency in Practice Bundle by Heinz Kabutz
10 Java Multithreading and Concurrency Best Practices
Top 50 Multithreading and Concurrency Questions in Java
Top 5 Multithreading and Concurrency course for Java programmers
6 Concurrency Books Java developer should read

Closing Notes

Thanks for reading this article so far. You might be thinking that there this is trivial but I tell you that it's an important concept and important for both writing correct concurrent programs as well for doing well on interviews.

At the end of the day, you should have enough knowledge and experience about the things mentioned here.

Good luck with your Concurrent Programming journey! It's certainly not going to be easy, but by following this roadmap and guide, you are one step closer to becoming the better developer, you always wanted to be

If you like this article then please consider following me on twitter(javinpaul. if you'd like to be notified for every new post and don't forget to followjavarevisited on Twitter!

P.S.- If you want to learn Java and Multithreading and looking for some free courses, please check Java Multithreading --- A #FREE course to start with.

Oldest comments (0)