Writing linear programs, while being a lot easier than concurrent programming, is a thing of the past. Linear programming was effective while Moore's Law held; however, as raw processing speed has currently hit a brick wall we have had to look at executing code in parallel. With more and more systems being built with multiple processors with multiple cores each, not taking advantage of them is poor programming. This limits the scalability, responsiveness, and performance of any program. To make things worse, many that code using Java still operate linearly even though threads permeate Java's system. Servlets operate using threads and can be concurrently accessed by multiple requests from users, GUI frameworks use threads underneath to retain responsiveness, the garbage collector operates in separate threads of it own, and etc. They are everywhere. If a program is being created without concurrency in mind, you run the great risk of inadvertently creating errant code because even if you yourself don't use multiple threads, that doesn't mean there aren't any there to access it. If there are multiple threads accessing the same mutable (changeable) variables, and those variables aren't properly synchronized, your program is broken. End of story. It may look like your code works initially, and it may work correctly for years to come, but it all amounts to lucky/unlucky timing. The worst time to see that the code is broken is when it fails in production under heavy load (and no doubt that is when it will happen because of the system having so much going on).
State
Concurrent programming is not defined by using threads and locks; rather, it is all about maintaining state. Threads and locks are the building blocks that we use to maintain state with concurrent access. An object's state is encompassed by the instance variables, static variables, or other dependent objects. When we talk about thread-safety, it may sound like we are talking about code, but what we are really saying is that we are trying to protect data by controlling concurrent access to the data.
Ways to Manage It
There are three primary ways in Java to maintain a class's state:
- Don't share state across threads (encapsulation).
- Make state variables immutable (unchangeable).
- Use synchronization techniques whenever accessing state variables.
It is important to remember to encapsulate synchronization inside an object so that when anything uses it, it doesn't have to worry about implementing its own synchronization outside of the object for the object. Stateless objects are always thread-safe, because there is nothing it has to remember or keep track of during its execution. If a single element of state is added to a stateless class, then it will be thread-safe if and only if the state is fully managed by a thread-safe object. When there are multiple variables that comprise an object's state, it is important to know which ones are dependent upon each other, and which ones that aren't. If there are 2 or more variables that are related in some fashion are accessed by more than one thread could result in the 2 variables getting out of sync (meaning the data contained within them doesn't match up). If the variables are independent of each other, the synchronization may be exclusive to each variable. This means that each one can be read, modified, or written to without worrying what the others are.
Final Thought
Concurrent programming is difficult at first, but it also not going away... ever. The only way to get better at is to read about it, read it again, and do it until my head and fingers hurt. Repetition is the mother of knowledge. That is the only way this will get any easier.
No comments:
Post a Comment