Creating Thread
- Override Run method of Thread and call Thread.start()
- 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