Hello guys, writing multi-threaded and concurrent programs is not easy, not even in Java. Even senior developers, including myself, make mistakes while writing concurrent Java applications. This is also one of the trickiest areas of Java programming language, where misconceptions outnumber concepts. Considering the amount of misconception an average Java programmer has about multi-threading and concurrency, I thought to start a new series about common multi-threading mistakes done by Java programmers; what is a better way to learn from common real word mistakes.
Learning from mistakes has another name Experience, but if you only learn from your mistakes then there are only limited things you can learn, but if you learn from other people's mistakes, you can learn much more in a short span of time.
Have you ever thought, Why writing multi-threaded code is difficult? IMHO, the primary reason for this is that it multi-threading makes it hard for a code to speak for itself.
Learning from mistakes has another name Experience, but if you only learn from your mistakes then there are only limited things you can learn, but if you learn from other people's mistakes, you can learn much more in a short span of time.
Have you ever thought, Why writing multi-threaded code is difficult? IMHO, the primary reason for this is that it multi-threading makes it hard for a code to speak for itself.
Programmers read code sequentially to understand how it's executed, but it is only correct if one and only one thread is executing it. That's why Single-threaded code is easy to read and debug.
As soon as two threads come into the picture, It becomes very difficult to make a prediction about how your code behaves, especially in the absence of any synchronization rules e.g. rules enforced by the Java Memory Model.
Without JMM you can not make correct predictions about your code in a multi-threaded environment, because it's possible for one thread to stop at an arbitrary point and another thread at different points.
The situation becomes even more tricky if those threads are sharing data between them e.g. in form of objects, a poorly written multi-threaded program can cause deadlock, race condition, and responsiveness issues, which will prevent a Java application to fulfill its promise.
I hope, in this series we can learn from each other's mistakes and take a step forward on writing correct multi-threaded applications in Java.
And, if you are serious about mastering Java multi-threading and concurrency then I also suggest you take a look at the Java Multithreading, Concurrency, and Performance Optimization course by Michael Pogrebinsy on Udemy. It's an advanced course to become an expert in Multithreading, concurrency, and Parallel programming in Java with a strong emphasis on high performance
Consider the following code :
What Does It Print?
(a) KingKong
(b) KongKing
(c) It varies
(d) Compile time error
We had this question in our Java written test and you will be surprised by the percentage of answers, whopping 50% answers It varies, 10% says compile-time error, another 15% picks answer a KingKong, and the rest of 25% chooses KongKing.
As soon as two threads come into the picture, It becomes very difficult to make a prediction about how your code behaves, especially in the absence of any synchronization rules e.g. rules enforced by the Java Memory Model.
Without JMM you can not make correct predictions about your code in a multi-threaded environment, because it's possible for one thread to stop at an arbitrary point and another thread at different points.
The situation becomes even more tricky if those threads are sharing data between them e.g. in form of objects, a poorly written multi-threaded program can cause deadlock, race condition, and responsiveness issues, which will prevent a Java application to fulfill its promise.
I hope, in this series we can learn from each other's mistakes and take a step forward on writing correct multi-threaded applications in Java.
And, if you are serious about mastering Java multi-threading and concurrency then I also suggest you take a look at the Java Multithreading, Concurrency, and Performance Optimization course by Michael Pogrebinsy on Udemy. It's an advanced course to become an expert in Multithreading, concurrency, and Parallel programming in Java with a strong emphasis on high performance
Multithreading and Concurrency Mistake in Java - Using run() in place of start()
I am starting with one of the simplest examples, this is a very common mistake by junior programmers and caused by half knowledge. They know that anything written in the run() method of Runnable interface or Thread class will execute in another thread but don't know how to create another thread in JVM.Consider the following code :
class KingKong { public static synchronized void main(String[] args) { Thread t = new Thread() { public void run() { kong(); } }; t.run(); System.out.print("King"); } public static synchronized void kong() { System.out.print("Kong"); } }
What Does It Print?
(a) KingKong
(b) KongKing
(c) It varies
(d) Compile time error
We had this question in our Java written test and you will be surprised by the percentage of answers, whopping 50% answers It varies, 10% says compile-time error, another 15% picks answer a KingKong, and the rest of 25% chooses KongKing.
We also ask them to write an explanation of why they choose a particular answer, just to avoid picking someone who is guessing their way.
The 50% developer, who chooses It varies, mentioned that there is no guarantee when a thread will start, so it is possible that if the main thread finishes first it will print KongKing and if the new thread executes before the main thread.
Wow, what do you say about these developers, seems a decent lot of programmer who knows some part of multi-threading but overlooked critical detail. The next 10% programmer, who chose Compile time error was unsure whether the main method can be synchronized or not and thought that compiler will not like it.
Next 15% says because "King" comes first in code, it will be printed first and "Kong" will be printed later.
The last 25% who chose "KongKing" are the people who got it correct. We were literally disappointed with these numbers because it wasn't such a difficult or a tricky question, but I agree sometimes it's difficult to spot a typo and that's what makes this error very hard to debug.
The correct answer is "KongKing" and this is because of one typo in the code. The intention of this code is to create a multi-threaded program, but because of t.run() it actually turned into a single-threaded program.
In Java, though it is true that calling Thread.start() will call Runnable.run() method but the complete truth is that calling start() actually creates a new thread and that new thread executes the run() method.
The 50% developer, who chooses It varies, mentioned that there is no guarantee when a thread will start, so it is possible that if the main thread finishes first it will print KongKing and if the new thread executes before the main thread.
Wow, what do you say about these developers, seems a decent lot of programmer who knows some part of multi-threading but overlooked critical detail. The next 10% programmer, who chose Compile time error was unsure whether the main method can be synchronized or not and thought that compiler will not like it.
Next 15% says because "King" comes first in code, it will be printed first and "Kong" will be printed later.
The last 25% who chose "KongKing" are the people who got it correct. We were literally disappointed with these numbers because it wasn't such a difficult or a tricky question, but I agree sometimes it's difficult to spot a typo and that's what makes this error very hard to debug.
Why Code Print KongKing and not KingKong?
In Java, though it is true that calling Thread.start() will call Runnable.run() method but the complete truth is that calling start() actually creates a new thread and that new thread executes the run() method.
If you directly call the run() method then no new thread will be created and the thread which is running the code will go to the run() and execute it first and then come back to its previous point.
Like in this case, the main thread will execute the run() method first, and thus print "Kong" before coming back and printing "King", that's why the output is "KongKing".
Like in this case, the main thread will execute the run() method first, and thus print "Kong" before coming back and printing "King", that's why the output is "KongKing".
When I quizzed about these to some programmer who was otherwise good but got this answer incorrect insisted that run() will call on a new thread because they are calling as t.run() where t is a new thread object.
So apart from a typo, this is the key misconception some Java programmer has. This is even more fundamental in nature because it highlights the difference between code and thread.
So apart from a typo, this is the key misconception some Java programmer has. This is even more fundamental in nature because it highlights the difference between code and thread.
Here definitely run() is called on t, which is a new thread, but the thread which is executing code is not thread t, but the main thread. t is not yet started because you have not called the start() method.
If you copy paste the above code in Eclipse IDE and debug it you will see the truth, as shown below.
You can see that we have put the breakpoint right at the point where the run() method is called i.e. t.run(). When you step Into this method, you will see that the main thread is executing the run() method and not the new thread.
Now if we just changed the t.run() to t.start(), your program will become multi-threaded and a new thread will be created when the main thread will execute line t.start(), later run() method will be called in this new thread, here is the screenshot of that.
That's all in the first post of my new series of common Java Multi-threading mistakes. Always use the start() method to start new threads and make your program multi-threaded, don't call the run() method directly.
If you copy paste the above code in Eclipse IDE and debug it you will see the truth, as shown below.
You can see that we have put the breakpoint right at the point where the run() method is called i.e. t.run(). When you step Into this method, you will see that the main thread is executing the run() method and not the new thread.
Now if we just changed the t.run() to t.start(), your program will become multi-threaded and a new thread will be created when the main thread will execute line t.start(), later run() method will be called in this new thread, here is the screenshot of that.
That's all in the first post of my new series of common Java Multi-threading mistakes. Always use the start() method to start new threads and make your program multi-threaded, don't call the run() method directly.
The compiler doesn't prevent you but it creates subtle bugs.
By the way, the difference between the start() and run() method is also a very common question in Java interviews.
Let me know how do you find this article and don't forget to share what multi-threading issues you have faced and what lessons you have learned from them. On a closing note, I would share one important tip to understand multi-threading better, debug it.
Yes debugging will tell you how many threads are currently executing your code, you can see their stack trace, values of variables they are holding, and on which lock they are locking. Debugging a multithreaded program is not easy, but once you do it a couple of times, you will find it immensely useful.
Let me know how do you find this article and don't forget to share what multi-threading issues you have faced and what lessons you have learned from them. On a closing note, I would share one important tip to understand multi-threading better, debug it.
Yes debugging will tell you how many threads are currently executing your code, you can see their stack trace, values of variables they are holding, and on which lock they are locking. Debugging a multithreaded program is not easy, but once you do it a couple of times, you will find it immensely useful.
Other Java Multithreading Interview Questions you may like to explore
Thanks for reading this article. If you like this tricky multithreading problem then please share it with your friends and colleagues. If you have any suggestions or feedback then please drop a comment.
- Top 50 Java Thread Interview Questions with Answers (list)
- Top 15 Multithreading and Concurrency Questions from Investment banks (see here)
- 133 Core Java Interview Questions from the last 5 years (see here)
- How volatile variable works in Java? (answer)
- Top 10 Java Concurrency and multi-threading best practices (article)
- Top 5 Courses to learn Multithreading and Concurrency in Java (courses)
- Top 10 Courses to learn Java in-depth (courses)
- 10 Courses to Crack Java Interviews for Beginners (courses)
- Top 5 courses to Learn Java Performance Tuning (courses)
- What is happens-before in Java Concurrency? (answer)
- Top 12 Java Concurrency Questions for Experienced Programmers (see here)
- Top 5 Books to learn Java Concurrency in-depth (books)
- Difference between start() and run() method in Java? (answer)
- 6 Books to learn Multithreading and Concurrency in Java (books)
- 10 Advanced Core Java Courses for Experienced programmers (course)
Thanks for reading this article. If you like this tricky multithreading problem then please share it with your friends and colleagues. If you have any suggestions or feedback then please drop a comment.
P. S. - If
you are a Java beginner and want to learn multithreading and concurrency and looking for some free courses to start with then you can also check out this free Java Multithreading course on Udemy. It is a good free course to learn Java Concurrency as well.
13 comments :
Another common mistake is during synchroniazation of static variable, instead of class level lock, we use object level lock using this variable in synchronized block
Yes, you explained it correctly but one thing you forget to share is that t is a thread class object and its having by default threadness feature but in first scenario thread t didn't execute run method just because thread t was in runnable state not in running state of thread life cycle, Once thread t execute t.start method then only it went to running state of life cycle.
Hi Javin , i have subscribed your posts through email. I like this post very simple and concise. I just trying to synchronizing HashMap. Can you provide some link to understand it..
one more thing...Now your blog looks good with this font size.
Thank you.
Hello Muralidhar, Thanks for you comments. Indeed Synchronizing HashMap is not a good idea in world of ConcurrentHashMap, You may want to check my post about CHM here
@Kaushik, you made an interesting point. I have seen lots of subtle threading bugs involving static variables.
Very good explantion...thanks. In mutlithread programming we should also think for 'thread-safe' code whenever it is required.
Hello paul,
I am regular visitor of java revisited from past 3 years. I really love each and every article you share here. This article cleared some of my doubts regarding multi threaded programming in java.
Thank you,
Regards:
Srinath Reddy.
I remember you Srinath, welcome back :) Glad this article help you to understand multi-threading in Java better.
@Jitendra, I agree with you, especially if you are sharing object, consider making them Immutable which are inherently thread-safe or employ synchronization, thread local variable to make it thread-safe.
Hello Javin,
Its unfortunate for me that I came to know about your blogspot yesterday only. Your explanation is simple and descent to understand for naive developers like me.
Thanks a ton.
Your explanation is awesome and so easy to understand. Thanks ...
That's really a nice work. Thanks...
Thx Unknown, glad you find this multithreading article helpful.
Post a Comment