Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Best Practices for Thread-Safety & Encapsulation in Java: 2007 JavaOne Conference, Exams of Programming Languages

Insights from the 2007 javaone sm conference session ts-2388 on effective thread-safety and encapsulation in java applications. Topics include understanding thread-safety, documenting it, and using @guardedby annotations. Encapsulation, immutability, and synchronization are also discussed to ensure correctness and scalability.

Typology: Exams

Pre 2010

Uploaded on 07/30/2009

koofers-user-4dj
koofers-user-4dj 🇺🇸

10 documents

1 / 37

Toggle sidebar

Related documents


Partial preview of the text

Download Best Practices for Thread-Safety & Encapsulation in Java: 2007 JavaOne Conference and more Exams Programming Languages in PDF only on Docsity! 2007 JavaOneSM Conference | Session TS-2388 | TS-2388 Effective Concurrency for the Java™ Platform Brian Goetz Senior Staff Engineer Sun Microsystems, Inc. brian.goetz@sun.com 2007 JavaOneSM Conference | Session TS-2388 | 2 The Big Picture Writing correct concurrent code is difficult, but not impossible Using good object-oriented design techniques can make it easier 2007 JavaOneSM Conference | Session TS-2388 | 5 Agenda Introduction Rules for Writing Thread-Safe Code Document Thread-Safety Intent and Implementation Encapsulate Data and Synchronization Prefer Immutable Objects Exploit Effective Immutability Rules for Structuring Concurrent Applications Think Tasks, Not Threads Build Resource-Management Into Your Architecture Decouple Identification of Work from Execution Rules for Improving Scalability Find and Eliminate the Serialization 2007 JavaOneSM Conference | Session TS-2388 | 6 Introduction ● This talk is about identifying patterns for concurrent code that are less fragile ● Conveniently, many are the good practices we already know ● Though sometimes we forget the basics ● Feel free to break (almost) all the rules here ● But be prepared to pay for it at maintenance time ● Remember the core language value: Reading code is more important than writing code 2007 JavaOneSM Conference | Session TS-2388 | 7 Agenda Introduction Rules for Writing Thread-Safe Code Document Thread-Safety Intent and Implementation Encapsulate Data and Synchronization Prefer Immutable Objects Exploit Effective Immutability Rules for Structuring Concurrent Applications Think Tasks, Not Threads Build Resource-Management Into Your Architecture Decouple Identification of Work from Execution Rules for Improving Scalability Find and Eliminate the Serialization 2007 JavaOneSM Conference | Session TS-2388 | 10 Document Thread-Safety ● Use @GuardedBy to document your locking protocols ● Annotating a field with @GuardedBy("this") means: ● Only access the field when holding the lock on “this” @ThreadSafe public class PositiveInteger { // INVARIANT: value > 0 @GuardedBy("this") private int value = 1; public synchronized int getValue() { return value; } public void setValue(int value) { if (value <= 0) throw new IllegalArgumentException(....); synchronized (this) { this.value = value; } } } ● Simplifies maintenance and avoids common mistakes ● Like adding a new code path and forgetting to synchronize ● Improper maintenance is a big source of concurrency bugs 2007 JavaOneSM Conference | Session TS-2388 | 11 Document Thread-Safety ● For primitive variables, @GuardedBy is straightforward ● But what about @GuardedBy("this") Set<Rock> knownRocks = new HashSet<Rock>(); ● There are three different types of potentially mutable state ●The knownRocks reference ●The internal data structures in the HashSet ●The elements of the collection ● Which types of state are we talking about? All of them? ● It varies, but we can often tell from context ●Are the elements owned by the class, or by clients? ●Are the elements thread-safe? ●Is the reference to the collection mutable? @GuardedBy("this") final Set<Rock> knownRocks = .... 2007 JavaOneSM Conference | Session TS-2388 | 12 knownRocks HashSet<Rock> Rock Rock Rock Rock ● For complicated data structures, draw a diagram identifying ownership and synchronization policies ● Color each state domain with its synchronization policy @ThreadSafe public class Rock { .... } @GuardedBy("this") final Set<Rock> knownRocks = new HashSet<Rock>(); ● Very effective for designing and reviewing code! ● Frequently identifies gaps or inconsistencies in synchronization policies Document Thread-Safety 2007 JavaOneSM Conference | Session TS-2388 | 15 Encapsulate Data and Synchronization ● Encapsulation promotes clear, maintainable code ● Reduces scope of effect of code changes ● Encapsulation similarly promotes thread safety ● Reduces how much code can access a variable ● And therefore how much be examined to ensure that synchronization protocols are followed ● Thread safety is about coordinating access to shared mutable data ● Shared—might be accessed by more than one thread ● Mutable—might be modified by some thread ● Less code that accesses a variable means fewer opportunities for error 2007 JavaOneSM Conference | Session TS-2388 | 16 Encapsulate Data and Synchronization ● Encapsulation makes it sensible to talk about individual classes being thread-safe ● A body of code is thread-safe if: ● It is correct in a single-threaded environment, and ● It continues to be correct when called from multiple threads ● Regardless of interleaving of execution by the runtime ● Without additional coordination by callers ● Correct means conforms to its specification ● Often framed in terms of invariants and postconditions ● These are statements about state ● Can’t say a body of code guarantees an invariant unless no other code can modify the underlying state ● Thread-safety can only describe a body of code that manages all access to its mutable state ● Without encapsulation, that's the whole program 2007 JavaOneSM Conference | Session TS-2388 | 17 Encapsulate Data and Synchronization ● Is this code correct? Is it thread-safe? public class PositiveInteger { // INVARIANT: value > 0 @GuardedBy("this") public int value = 1; public synchronized int getValue() { return value; } public synchronized void setValue(int value) { if (value <= 0) throw new IllegalArgumentException(....); this.value = value; } } ● We can’t say unless we examine all the code that accesses value ●Doesn’t even enforce invariants in single-threaded case ●Difficult to reason about invariants when data can change at any time ●Can’t ensure data is accessed with proper synchronization 2007 JavaOneSM Conference | Session TS-2388 | 20 Encapsulate Data and Synchronization ● If a class imposes invariants on its state, it must also provide its own synchronization to protect these invariants ● Even if component classes are thread-safe! ● UserManager follows The Rule ● But still might not be thread-safe! public class UserManager { // Each known user is in exactly one of {active, inactive} private final Set<User> active = Collections.synchronizedSet(new HashSet<User>()); private final Set<User> inactive = Collections.synchronizedSet(new HashSet<User>()); // Constructor populates inactive set with known users public void activate(User u) { if (inactive.remove(u)) active.add(u); } public boolean isKnownUser(User u) { return active.contains(u) || inactive.contains(u); } } 2007 JavaOneSM Conference | Session TS-2388 | 21 Encapsulate Data and Synchronization ● In UserManager, all data is accessed with synchronization ● But still possible to see a user as neither active nor inactive ● Therefore not thread-safe—can violate its specification! ● Need to make compound operations atomic with respect to one other ● Solution: synchronize UserManager methods public class UserManager { // Each known user is in exactly one of {active, inactive} private final Set<User> active = Collections.synchronizedSet(...); private final Set<User> inactive = Collections.synchronizedSet(...); public synchronized void activate(User u) { if (inactive.remove(u)) active.add(u); } public synchronized boolean isKnownUser(User u) { return active.contains(u) || inactive.contains(u); } public Set<User> getActiveUsers() { return Collections.unmodifiableSet(active); } } 2007 JavaOneSM Conference | Session TS-2388 | 22 Encapsulate Data and Synchronization ● The problem was that synchronization was specified at a different level than the invariants ● Result: atomicity failures (race conditions) ● Could fix with client-side locking, but is fragile ● Instead, encapsulate enforcement of invariants ● All variables in an invariant should be guarded by same lock ● Hold lock for duration of operation on related variables ● Always provide synchronization at the same level as the invariants ● When composing operations on thread-safe objects, you may end up with multiple layers of synchronization ● And that’s OK! 2007 JavaOneSM Conference | Session TS-2388 | 25 Prefer Immutable Objects ● An immutable object is one whose ● State cannot be changed after construction ● All fields are final ● Not optional—critical for thread-safety of immutable objects ● Immutable objects are automatically thread-safe! ● Simpler ● Can only ever be in one state, controlled by the constructor ● Safer ● Can be freely shared with unknown or malicious code, who cannot subvert their invariants ● More scalable ● No synchronization required when sharing! ● (See Effective Java technology Item #13 for more) 2007 JavaOneSM Conference | Session TS-2388 | 26 Prefer Immutable Objects ● Most concurrency hazards stem from the need to coordinate access to mutable state ● Race conditions and data races come from insufficient synchronization ● Many other problems (e.g., deadlock) are consequences of strategies for proper coordination ● No mutable state → no need for coordination ● No race conditions, data races, deadlocks, scalability bottlenecks ● Identify immutable objects with @Immutable ● @Immutable implies @ThreadSafe ● Don’t worry about the cost of object creation ● Object lifecycle is generally cheap ● Immutable objects have some performance benefits too 2007 JavaOneSM Conference | Session TS-2388 | 27 Prefer Immutable Objects ● Even if immutability is not an option, less mutable state can still mean less coordination ● Benefits of immutability apply to individual variables as well as objects ● Final fields have special visibility guarantees ● Final fields are simpler than mutable fields ● Final is the new private ● Declare fields final wherever practical ● Worth doing extra work to avoid making fields nonfinal ● In synchronization policy diagrams, final variables provide a synchronization policy for references ● But not the referred-to object ● If you can’t get away with full immutability, seek to limit mutable state as much as possible 2007 JavaOneSM Conference | Session TS-2388 | 30 Find the Serialization ● Processor speeds flattened out around 2003 ● Moore's law now gives us more cores, not faster ones ● Increasing throughput means keeping more cores busy ● Can no longer just buy a faster box to get a speedup ● Must write programs that take advantage of additional CPUs ● Just adding more cores may not improve throughput ● Tasks must be amenable to parallelization Source: (Graphic © 2006 Herb Sutter) 2007 JavaOneSM Conference | Session TS-2388 | 31 Find the Serialization ● System throughput is governed by Amdahl’s Law ● Divides work into serial and parallel portions ● Serial work cannot be sped up by adding resources ● Parallelizable work can be ● Most tasks have a mix of serial and parallel work ● Harvesting crops can be sped up with more workers ● But additional workers will not make them grow any faster ● Amdahl’s Law says: ● F is the fraction that must be executed serially ● N is the number of available workers ● As N → infinity, speedup → 1/F ● With 50% serialization, can only speed up by a factor of two ● No matter how many processors Speedup  1 F 1−F  N  2007 JavaOneSM Conference | Session TS-2388 | 32 Find the Serialization ● Every task has some sources of serialization ● You just have to know where to look ● The primary source of serialization is the exclusive lock ● The longer locks are held for, the worse it gets ● Even when tasks consist only of thread-local computation, there is still serialization inherent in task dispatching while (!shutdownRequested) { Task t = taskQueue.take(); // potential serialization Result r = t.doTask(); resultSet.add(result); // potential serialization } ● Accessing the task queue and the results container invariably involves serialization 2007 JavaOneSM Conference | Session TS-2388 | 35 For More Information ● Other sessions ● TS-2220: Testing Concurrent Software ● TS-2007: Improving Software Quality with Static Analysis ● BOF-2864: Debugging Data Races ● Books ● Java Concurrency in Practice (Goetz, et al) ● See http://www.jcip.net ● Concurrent Programming in Java (Lea) ● Effective Java (Bloch) 2007 JavaOneSM Conference | Session TS-2388 | 36 Q&A Effective Concurrency for the Java Platform Brian Goetz, Sun Microsystems 2007 JavaOneSM Conference | Session TS-2388 | TS-2388 Effective Concurrency for the Java™ Platform Brian Goetz Senior Staff Engineer Sun Microsystems, Inc. brian.goetz@sun.com
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved