Concurrency
Concurrency is a decoupling strategy itself, separating what gets done from when it gets done. This post we will look at some common issues with writing and maintaining clean concurrent code, as well as testing approaches for concurrent code.
Single Responsibility Principle
Any given method, class, component should have a single reason to change. Keep your concurrency related code separate from the other code.
Limit the Scope of Data
Two threads modifying shared data can interfere with each other, and cause unexpected behaviour. Encapsulate the data to avoid any unexpected shared data between threads. Limit the access of any data that may be shared.
Use Copies of Data
Copy objects and treat them as read-only if possible.
Prioritize Independence
Write your code such that it exists in its own world, sharing no data with any other thread. Partition data into independent subsets that can be operated on by independent threads, possibly in different processors.
Producer-Consumer
Producer creates some work and places it into a bound queue. Consumer acquires that work from the queue and completes it.
Reader-Writer
When you have a shared resource that primary serves as a source of information for readers, but which is occasionally updated by writers, throughput is an issue.
Synchronization
Avoid using more than one method on a shared object. If you use locks, keep the synchronized code as small as possible.
Testing
- Get non-threaded code working first. Don't debug both non-threading bugs and threading bugs.
- Treat spurious failures as candidate threading issues.
- Make your thread-based code especially pluggable so that you can run it in various configurations.
- Instrument your code to try and force failures.