Creating Thread

  1. Override Run method of Thread and call Thread.start()
  2. Override run method of a Runnable, pass it to a thread contructor and then call start() new Thread(Runnable runnable).start()

Legacy Pitfalls

Avoid manually spawning raw threads (new Thread().start()) or sizing custom thread pools in production code unless working on low-level framework infrastructure.

Synchronize

Synchronization in Java is a mechanism that ensures that multiple threads do not access shared resources concurrently, which could lead to inconsistent states or race conditions. By using synchronization, only one thread can access a resource at a time, maintaining thread safety. This is especially important when multiple threads are modifying or reading shared data.

  • Intrinsic Lock
  • When a synchronized keyword is placed on a method such as on withdraw(int money), it has the same effect as wrapping all of a method’s code in synchronized(this)
  • it can have a huge effect on performance as Locks are very slow

Cite

Locks are incredibly expensive because they require arbitration when contended. This arbitration is achieved by a context switch to the operating system kernel which will suspend threads waiting on a lock until it is released. During such a context switch, as well as releasing control to the operating system which may decide to do other house-keeping tasks while it has control, execution context can lose previously cached data and instructions. This can have a serious performance impact on modern processors.

Best Practice

  • Ideally we want to avoid using synchronized where possible.
  • Minimising the size of the code block that is synchronized is a good start.
  • You can lock on specific objects, or use a lock object if using a primitive, so that the entire object does not need to be contended.

Lock

java.util.concurrent.locks ReentrantLock