Concurrency
Study Questions
Disclaimer: These questions can and should be augmented and / or replaced by questions raised by the participating study group members. Please bring your own questions to each study session!
1.1 Using Concurrency Constructs (1-18)
Session 1
When would you want to create a daemon Thread?
Why have suspend, resume, stop, destroy been deprecated?
When would it be useful to create a ThreadGroup?
1.2 Objects and Concurrency (19-36)
What classes of problems can concurrent programs help solve (hint: optimization)?
What benefits do concurrent programs offer over sequential programs?
How can we decide whether a system needs separate machines, processors, processes, or threads?
What are the trade-offs (costs v. benefits) of each kind of separation?
What thread scheduling strategies does Java support?
1.3 Design Forces (37-56)
Session 2
How are performance and reusability related to safety and liveness? What other qualities contribute to safety and liveness?
What other kinds of safety concerns are there besides type safety and multithread safety (hint: consider transactions and ACID properties)?
Doug Lea lists several qualities that can be used to measure performance. How can we measure reuse and reusability?
1.4 Before/After Patterns (57-68)
Session 3
What are the benefits and costs of the various approaches to implementing before/after patterns?
Is the cost of instantiating a method adapter worth the benefit of factoring out the lifecycle guarantees into a single location (also see: Resource Manager)?
2.1 Immutability (69-74)
Session 4
How can the fields of an object become accessible before its construction is complete?
Why is it important to ensure that flyweights are completely constructed before they are published?
2.2 Synchronization (75-98)
When would it be useful to know which of several threads owns a lock?
When and why is fairness important during lock acquisition?
What are the benefits of reentrant locking? Are there any drawbacks?
When would it be appropriate to use a volatile field instead of synchronized methods or blocks?
2.3 Confinement (99-116)
Session 5
What are the trade-offs associated with tail-call hand-offs?
Given the consequences of thread-based confinement (page 106), which of the available options seems most flexible?
When would thread-based confinement be inappropriate?
On page 112, the take protocol has often been called orphan and the put protocol often called adopt (see Taligent's Guide to Designing Programs). How can these two protocols (however named) be combined to implement a clean and confined resource transfer? (hint: use the stack, e.g., x.adoptResource(y.orphanResource()))
2.4 Structuring and Refactoring Classes (117-146)
Sessions 6 + 7
What are semantic guarantees (hint: class invariants, method post-conditions)? How can they be weakened?
Given the fragility of double-checked locks and the likelihood that they will break or be used inappropriately, would you ever use them? If so, when?
Does a "single giant lock" offer a significant opportunity for refactoring?
Should the use of open calls always be documented to clarify the contractual obligations of the called methods?
Is splitting a class (via refactoring) preferable to merely splitting a lock within the class? When would one be preferable to the other?
Are explicitly immutable interfaces preferable to runtime immutability (hint: catching contract violations during compilation rather than execution)?
How can the Resource Manager pattern be adapted to enforce the correct usage of resources in open containers?
2.5 Using Lock Utilities (147-158)
Session 8
How can the awkward before/after construction on page 148 be simplified (hint: make acquire and release reentrant)?
What kind of method adapter signature will support passed parameters and returned results?
Can shared resource allocations be pre-empted, or must Java threads always coordinate and cooperate?
Do coupled locks introduce a greater likelihood of races and deadlocks between competing threads?
If so, how can that be resolved (hint: coupled lock managers)?
What kind(s) of fairness policy(s) will ensure that read-write locks prevent starvation between contending readers and writers?
3.1 Dealing with Failure (159-178)
Session 9
When is each of the six general responses to failed actions appropriate (termination, continuation, rollback, recovery, retry, handlers)?
When are thread interruption checks automatically performed within the Java library?
When are thread interruption checks not performed, i.e., when are threads dormant while waiting for a resource?
Why are lock utilities useful for cancellation protocols (hint: reduced dormancy)?
What kinds of safety concerns arise in relation to Thread.stop, i.e., why was it deprecated?
What (relatively) safe alternatives are there for terminating a thread and diminishing its use of system resources if the thread fails to terminate?
3.2 Guarded Methods (179-198)
Session 10
How do guarded methods extended synchronized methods? How do guards differ from traditional conditionals?
How does concurrent constraint programming help solve state-based design problems?
What are the commonly used alternatives for representing state?
How do predicate states differ from enumerated states? What are their benefits?
When can starvation become an issue in state-based concurrent program designs?
How can slipped conditions and missed signals be avoided?
Why is notifyAll used more often than notify to awaken waiting threads?
Why is it better to avoid busy waits? What are better alternatives?
3.3 Structuring and Refactoring Classes (199-218)
Sessions 11 + 12
In general, how can logical state analysis help determine the optimal usage of wait and notify during state transition operations?
The state table on page 200 defines the states and the legal transitions for a BoundedBuffer. What additional information is needed to determine the optimal usage of wait and notify during the state transition operations?
How can conflicts between a large set of operation pairs be resolved with a minimum of custom code per each pair?
How can the examples for tracked states and conflict sets be improved with refactoring (hint: extract methods)?
When can starvation become an issue with readers and writers?
Why is it useful to separate functionality as non-public methods from concurrency control as public methods?
How can lockouts be avoided in nested monitors?
3.4 Using Concurrency Control Utilities (219-236)
Session 13
How are semaphores related to mutual exclusion locks, resource pools, bounded buffers, and synchronous channels?
In what kind of applications will fairness issues usually arise?
What is priority inversion, and how can it be countered?
What are the typical applications of binary latches?
What rarely useful mechanism finds an appropriate usage in latching variables?
When are exchangers useful (hint: double buffering)?
When are condition variables useful (hint: legacy code conversion)?
3.5 Joint Actions (237-248)
Session 14
What are some of the factors to consider when designing joint actions?
What is the main goal of joint action designs?
What are the general structure and behavior of classes involved in joint actions?
What are some of the conflict resolution strategies used to prevent deadlocks in joint action designs?
What is the best way to avoid design issues associated with joint actions?
3.6 Transactions (249-264)
Session 15
What are the four steps in the basic transaction protocol?
What are the two complementary sets of policies that can be applied to transaction protocols?
How do these two policies effect the design of transactional interfaces and implementations?
When would it make sense to support both optimistic and conservative transaction policies?
How can the detailed analysis of the structure of transaction policies help determine which to choose (hint: cost comparison)?
What is the relationship between a property constraint and the ability (right) to veto a property change?
3.7 Implementing Utilities (265-280)
Session 16
Given the complexity of the methods in Semaphore, how would you refactor them with Extract Method?
What are the potential performance costs of using notifyAll versus notify?
Given that single-threaded notification designs usually increase design complexity, will it usually be worth the performance gain to pursue such designs?
Why might collapsing the classes within a design that splits state-dependent actions make them more efficient?
Given the increased complexity from collapsing classes, when (if ever) would this approach be warranted?
Is there an appropriate utility class that could be used in place of WaitQueue for the FIFO semaphore?
In comparison with the suggested FIFO semaphore implementation, how could a priority semaphore be implemented?
How could a task-oriented semaphore for resolving conflict sets be designed?
How could the queuing policy for the various kinds of queue-based semaphores be factored out?
4.1 Oneway Messages (281-304)
Session 17
What data characteristics distinguish the various kinds of message formats described in section 4.1.1 (hint: binary v. text, instance v. class, event v. 1-way request)?
In an open call design, what will happen if the request arrival rate exceeds the request acceptance rate (which is determined by the local state update latency)?
What are some of the reasons one might use a thread-per-message design? What kind of limitations will usually be encountered with thread-per-message designs?
What trade-offs do thread pools introduce? How can thread pool saturation be addressed? How do web servers and app servers typically address saturation?
Given that a Swing event queue is single-threaded, can it be easily saturated? What are the observable consequences of such saturation? How can such saturation be eliminated?
How does the JDK Timer framework in java.util compare with that suggested in section 4.1.4.3? How might a Schedule be represented indepently of tasks, threads, Timers, and the system clock?
When using a busy-wait loop to manage event-driven tasks, would it be beneficial to use the number of tasks (or the average per some time period) to control the sleep / wait duration?
When commands do not arrive as units, a worker thead can stall. Is there an alternative to using a buffering scheme to prevent stalling (hint: test for available() >= N, where N is a fixed command length)?
4.2 Composing Oneway Messages (305-324)
Session 18
What are some of the goals satisfied by flow network designs (hint: see the end of section 4.2.1.2)?
What are some examples of systems from your development practice that either did benefit or would benefit from the use of a flow network design?
What were the idioms, patterns, and metaphors relevant to your designs?
How do they compare with those described in this section?
4.3 Services in Threads (325-342)
Session 19
How have you (or would you) use Thread.join and futures in your own concurrent program designs?
If the Callable interface in section 4.3.3.1 is awkward, how would you improve upon it or generate a design based on this idea?
How does the "elevator algorithm" from section 4.3.4 work? Is there any situation from your own coding practice where you (could) have applied this?
4.4 Parallel Decomposition (343-366)
Session 20
What are the primary goals we're trying to satisfy with task granularity and structure in fork/join decomposition solutions?
How do the forces represented by these goals trade off against each other?
What design techniques can be applied to balancing these forces, i.e., what frameworks and design steps can be used?
How can the number of forked subtasks be varied dynamically?
When are callback-based fork/join designs typically used?
When and how can trees improve the efficiency of fork/join designs?
Is there any situation from your own coding practice where you (could) have used a cyclic barrier?
4.5 Active Objects (367-376)
Session 21
What differentiates active objects from other kinds of objects?
Is there any situation from your own coding practice where you (could) have used active objects?
How do CSP processes and channels behave?
What benefits can be gained from using CSP in designs?
Is there any situation from your own coding practice where you (could) have used CSP?