←Older revision |
Revision as of 10:08, 12 February 2009 |
Line 1: |
Line 1: |
- | The [[Java]] synchronization model with all '''synchronized''', '''notify''' and '''wait''' its is commonly thought of as an example of [[monitor]]s. However with closer look one finds out that it is far different to the model used in [[wikipedia::Concurrent_Pascal|Concurrent Pascal]]. It is not that robust, it is not well enough integrated to the language and sort of feels like an assembly language with synchronization primitives than high-level abstraction provided by real [[monitor]]. However, it has yet another hidden flaw, kind of example of [[Copy Based Design]] problem: the [[Java Monitor]]s implant the [[monitor]] into [[wikipedia::Object_oriented_language|object oriented language]], in an object oriented style and that does not work. | + | The [[Java]] synchronization model with all its '''synchronized''', '''notify''' and '''wait''' is commonly thought of as an example of [[monitor]]s. However with closer look one finds out that it is far different to the model used in [[wikipedia::Concurrent_Pascal|Concurrent Pascal]]. It is not that robust, it is not well enough integrated to the language and sort of feels like an assembly language with synchronization primitives than high-level abstraction provided by real [[monitor]]. However, it has yet another hidden flaw, kind of example of [[Copy Based Design]] problem: the [[Java Monitor]]s implant the [[monitor]] into [[wikipedia::Object_oriented_language|object oriented language]], in an object oriented style and that does not work. |
| | | |
| Imagine there is an '''Cache''' support class in some [[API]]: | | Imagine there is an '''Cache''' support class in some [[API]]: |
Line 5: |
Line 5: |
| <source lang="java" snippet="monitor.pitfalls.Cache"/> | | <source lang="java" snippet="monitor.pitfalls.Cache"/> |
| | | |
- | Its synchronization is sufficiently well designed. It never calls foreign code while holding own lock, which is one of necessary [[Deadlock Condition]]s. As such one would expect that there is no way to [[deadlock]] on the '''Cache'''s lock. However that would be false assumption. Simple call like: | + | Its synchronization is sufficiently well designed. It never calls foreign code while holding own lock, which is one of necessary [[Deadlock Condition]]s. As such one would expect that there is no way to [[deadlock]] on the '''Cache''''s own lock. However that would be false assumption. Simple call like: |
| | | |
| <source lang="java" snippet="monitor.pitfalls.brokencall"/> | | <source lang="java" snippet="monitor.pitfalls.brokencall"/> |
Line 18: |
Line 18: |
| </source> | | </source> |
| | | |
- | Moreover this all is achievable using the ''best'' [[Java]] synchronization practices. Just imagine there is a subclass of the '''Cache''' class which defines few properties and for better or worse guards them as [[Java Monitor]]: | + | Moreover this all is achievable using the ''best'' [[Java]] synchronization practices. How's that possible? |
| + | |
| + | Just imagine there is a subclass of the '''Cache''' class which defines few properties and for better or worse guards them as [[Java Monitor]]: |
| | | |
| <source lang="java" snippet="monitor.pitfalls.subclass"/> | | <source lang="java" snippet="monitor.pitfalls.subclass"/> |
| | | |
- | This code is not bulletproof. It notifies its listeners while holding own lock and as such this can lead to deadlocks. However it is common that people do these sort of mistakes when using an [[API]]. The [[API]] shall be ready to handle [[cluelessness|clueless]] clients. It is acceptable to let the clients of an [[API]] deadlock on their own locks, yet there is no reason to block the [[API]] itself. Yet this is the case: | + | This code is not bulletproof. It notifies its listeners while holding own lock and as such this can lead to deadlocks. However it is common that people do these sort of mistakes when using an [[API]]. The [[API]] shall be ready to handle such [[cluelessness|clueless]] clients. It is acceptable to let them deadlock on their own locks, yet there is no reason to block the [[API]] itself. It shall continue to work for other clients if possible. Yet this is the case in this example: |
| | | |
| <source lang="java" snippet="monitor.pitfalls.block.propertychange"/> | | <source lang="java" snippet="monitor.pitfalls.block.propertychange"/> |
| | | |
- | Simple call to '''get("123")''' deadlocks. Why? Because the [[Java Monitor]]s implant the [[monitor]] concept into object oriented world and in the process of doing so break the most fundamental assumption: the [[monitor]] shall be encapsulated. One shall always define all internal data structures and operations working on them in one monitor. This is not the case of [[Java]]'s synchronized methods at all. By default, the '''Cache''' and its subclass '''MultiplyCache''' share the same [[monitor]] lock! | + | Simple call to '''get("123")''' deadlocks. Why? Because the [[Java Monitor]]s implant the [[monitor]] concept into object oriented world and in the process of doing so break the most fundamental assumption: the [[monitor]] shall be encapsulated. |
| + | |
| + | One shall always define all internal data structures and all their operations working on them in one monitor. This is not the case of [[Java]]'s synchronized methods at all. By default, the methods in '''Cache''' and its subclass '''MultiplyCache''' share the same [[monitor]] lock! |
| | | |
| === Implications for [[API]] Design === | | === Implications for [[API]] Design === |
Line 36: |
Line 40: |
| Using ''synchronized'' methods in classes accessible to [[API]] clients also exposes these monitors to public. Moreover often unconsciously, which is even more dangerous. The fix is simple. Just hide the locks as private objects: | | Using ''synchronized'' methods in classes accessible to [[API]] clients also exposes these monitors to public. Moreover often unconsciously, which is even more dangerous. The fix is simple. Just hide the locks as private objects: |
| | | |
- | // TBD | + | <source lang="java" snippet="monitor.pitfalls.CacheOK"/> |
| | | |
| With a change like this the call | | With a change like this the call |
Line 42: |
Line 46: |
| <source lang="java" snippet="monitor.pitfalls.brokencall"/> | | <source lang="java" snippet="monitor.pitfalls.brokencall"/> |
| | | |
- | can never [[deadlock]] again, regardless how bad [[API]] clients one has. | + | can never [[deadlock]] again, regardless how bad of clueless [[API]] clients one has. In the name of [[cluelessness]] of your [[Java]] [[API]] users, don't forget to prefer private locks to '''synchronized''' methods. |