Sunday, December 30, 2012

Concurrency risks: thread safety, locking problems, deadlock

Concurrency risks

  • thread safety / correctness e.g. race condition (incorrect behaviour/result because a shared variable/resource is modified by another thread)
  • liveness hazard e.g. deadlock (the thread block by a lock), starvation (the thread doesn't chance for its turn since other threads have higher priorities)
  • performance hazard e.g. locking problems, too much context switching
  • difficult to test, debug, maintain

Thread safety

The main source of thread safety problem is the shared variable/resource. The solutions:
  • don't share variable (e.g. stateless servlet)
  • make variable immutable
  • use lock (synchronize in Java)
Race condition is the most common concurrency correctness problem. Pay attention for the compound actions (e.g. check then act, read then write). Using thread safe atomic objects  don't always guarantee the correctness, the compound actions themselves need to be atomic (e.g. using synchronize).

Deadling with performance problems due to locking

Improper / excessive lock usages can lead to liveness hazard & performance hazard. Tips to work with locking:

  • reduce the lock scope, for example: synchronize a block of codes instead of the whole method, delegated lock (e.g. using thread safe objects)
  • avoid locking lengthy operations (waiting user response, contended resource, long distance web service)
  • don't nested lock
  • Lock splitting / reduce lock granularity: use different locks for each object instead of using one lock in a long code.
  • use alternatives to locking: confinement / don't share object (e.g. use local variables, deepcopy to create local copy for each thread, use ThreadLocal), immutable object (final), volatile object.
  • provide deadlock resolution (e.g. timeout and then choose a victim)

Deadlock causes

  • Inconsistent lock ordering (e.g. thread 1 acquires lock on resource A then lock on resource B while thread 2 acquires lock B then A, so thread 2 will wait for thread 1 and vice versa) . Solution: provide global ordering (e.g. bash on hash code of the objects) instead of using dynamic/input-dependent  order.
  • Calling an locking alien method within a lock (double locking). Solution: open call (call without lock)
  • The limitation of resource capacity (e.g. we have 100 requests while the resource pool limit the connection to 10 so the other 90 have to wait). Solution: bigger capacity resource, clustering & load balancer, request throttling.
  • The thread is waiting for another thread result (that might a lengthy operation or even never finish). Solution: time out, refactor the flows to avoid waiting if possible, use FutureTask so that the computation can be started even before it's needed.

So why learning multithreading?

One famous book in Java suggests that we need to avoid using multithreading in our program due to its intricacy. Well, this is fine if you want to learn Java just for certification or to pass college exams, but in real life as a software developer there are many situations where you can't avoid to deal with multithreading situations, for example:
  • when you build a web application, typically the web server will manage many sessions serving requests from different clients so you need to be aware for example the effect of static variables in your servlet.
  • when you implement business process (since typical business process are parallel) e.g. exam papers processing.
  • when you modify data (e.g. in database) in multi user cases (e.g. via web application that will be accessed by multiple users), typically you need to implement lock during  data modification.
  • multi threading programming is inherent in many domains such as: database clusters, algorithm trading (dispatch multiple buy/sell orders), games programming, multi agents, simulation, peer to peer protocol, high performance scientific computing, multi core programming and many others.
Please see also Software guidelines for performance:

Source: Steve's blogs

Any comments are welcome :)


Java Concurrency in Practice

High-Performance Java Platform Computing: Multithreaded and Networked Programming

Effective Java

No comments: