After interviewing many software developers, I came to a need to write down many mistakes that people do.
Unfortunately, many software developers have troubles with multi threading.
Take deadlock concept, for example. This is what happens when you have a circular dependency betwen multiple threads (or one thread, in really complicated cases). Thread A waits for thread B, B waits for C… which in turn waits for A.
Easy… but somehow, many people have problem relating the deadlock to a cycle.
“A deadlock is when a thread tries to take a lock, but it is already taken!” – is one popular wrong answer.
This is wrong, because this is not a deadlock. This is normal flow control between two threads.
Some people do know what deadlock is, but they tend to confuse it with other problem in multithreaded applications – the race condition. Race condition occurs when multiple threads try to access same resource, and the final state of result depends on the order, in which it was accessed. That order is, unfortunately, undefined – unless we define it using our own flow control method, implemented with synchronization mechanisms. So a race condition is a problem, where a result depends on undefined behaviour, i.e. not defined well. Race condition is not a deadlock – it is a completely different beast. One rule of thumb – race condition happens when there are not enough locking, while deadlock is a sign that there is one lock too many.
Another manifestation of too much locks is starvation. Aquiring a lock is expensive operation, which does not have immediate positive impact on the software. So when we acquire lots of locks, we are waisting the CPU time. With enough waste, our threads can be low on the CPU time.
One particular case of starvation happens when we start prioritizing threads. When threads are prioritized, ones with higher priority should run faster than these with lower priority. But what does it mean, run faster? CPU tends to run on same speed all the time, unless it is overheated, or put to sleep. To make thread run faster, we should schedule it to run more often. However, there’s a trap: if a high priority thread needs to acquire resource that is taken by a lower priority thread, the high priority thread will wait until the low priority thread, which not scheduled to run as often as the high priority thread require, will release the resource. This means that the high priority thread becomes a low priority thread during its wait for a resource. This is, of course, the dreaded priority inversion problem.
I don’t really expect a Java programmer to be expert with priority inversions, but too many people mess with deadlocks….