From 9bc3c75ef97483632a580d76970dd0b7433b50b9 Mon Sep 17 00:00:00 2001 From: Asiel Leal Celdeiro <15990580+lealceldeiro@users.noreply.github.com> Date: Sun, 1 Oct 2023 00:04:39 +0300 Subject: [PATCH] Improve md format, shorten long lines --- JavaConcurrencyInPractice/Chapter01/README.md | 28 +++- JavaConcurrencyInPractice/Chapter02/README.md | 85 +++++++--- JavaConcurrencyInPractice/Chapter03/README.md | 156 +++++++++++------- 3 files changed, 181 insertions(+), 88 deletions(-) diff --git a/JavaConcurrencyInPractice/Chapter01/README.md b/JavaConcurrencyInPractice/Chapter01/README.md index d2cea53b..122ed05e 100644 --- a/JavaConcurrencyInPractice/Chapter01/README.md +++ b/JavaConcurrencyInPractice/Chapter01/README.md @@ -2,31 +2,43 @@ ## 1.1 A (very) brief history of concurrency -Threads allow multiple streams of program control flow to coexist within a process. They share process-wide resources such as memory and file handles, but each thread has its own program counter, stack, and local variables. Threads also provide a natural decomposition for exploiting hardware parallelism on multi-processor systems; multiple threads within the same program can be scheduled simultaneously on multiple CPUs. +Threads allow multiple streams of program control flow to coexist within a process. They share process-wide resources +such as memory and file handles, but each thread has its own program counter, stack, and local variables. Threads also +provide a natural decomposition for exploiting hardware parallelism on multi-processor systems; multiple threads +within the same program can be scheduled simultaneously on multiple CPUs. -Threads are sometimes called lightweight processes, and most modern operating systems treat threads, not processes, as the basic units of scheduling. +Threads are sometimes called lightweight processes, and most modern operating systems treat threads, not processes, as +the basic units of scheduling. ## 1.3 Risks of threads ### 1.3.1 Safety hazards -Thread safety can be unexpectedly subtle because, in the absence of sufficient synchronization, the ordering of operations in multiple threads is unpredictable and sometimes surprising. +Thread safety can be unexpectedly subtle because, in the absence of sufficient synchronization, the ordering of +operations in multiple threads is unpredictable and sometimes surprising. -In the absence of synchronization, the compiler, hardware, and runtime are allowed to take substantial liberties with the timing and ordering of actions, such as caching variables in registers or processor-local caches where they are temporarily (or even permanently) invisible to other threads. +In the absence of synchronization, the compiler, hardware, and runtime are allowed to take substantial liberties +with the timing and ordering of actions, such as caching variables in registers or processor-local caches where +they are temporarily (or even permanently) invisible to other threads. ### 1.3.2 Liveness hazards -The use of threads introduces additional safety hazards not present in single-threaded programs. Similarly, the use of threads introduces additional forms of _liveness failure_ that do not occur in single-threaded programs. +The use of threads introduces additional safety hazards not present in single-threaded programs. Similarly, the use +of threads introduces additional forms of _liveness failure_ that do not occur in single-threaded programs. -While _safety_ means “nothing bad ever happens”, liveness concerns the complementary goal that “something good eventually happens”. A liveness failure occurs when an activity gets into a state such that it is permanently unable to make forward progress (deadlock, starvation, livelock) +While _safety_ means “nothing bad ever happens”, liveness concerns the complementary goal that “something good +eventually happens”. A liveness failure occurs when an activity gets into a state such that it is permanently unable +to make forward progress (deadlock, starvation, livelock) ### 1.3.3 Performance hazards -Performance issues subsume a broad range of problems, including poor service time, responsiveness, throughput, resource consumption, or scalability. +Performance issues subsume a broad range of problems, including poor service time, responsiveness, throughput, +resource consumption, or scalability. ## 1.4 Threads are everywhere -Frameworks introduce concurrency into applications by calling application components from framework threads. Components invariably access application state, thus requiring that _all_ code paths accessing that state be thread-safe. +Frameworks introduce concurrency into applications by calling application components from framework threads. Components +invariably access application state, thus requiring that _all_ code paths accessing that state be thread-safe. The facilities described below all cause application code to be called from threads not managed by the application: diff --git a/JavaConcurrencyInPractice/Chapter02/README.md b/JavaConcurrencyInPractice/Chapter02/README.md index d2a87b93..2d0d60a6 100644 --- a/JavaConcurrencyInPractice/Chapter02/README.md +++ b/JavaConcurrencyInPractice/Chapter02/README.md @@ -1,12 +1,17 @@ # Chapter 2: Thread Safety -Writing thread-safe code is, at its core, about managing access to _state_, and in particular to _shared, mutable state_. +Writing thread-safe code is, at its core, about managing access to _state_, and in particular to _shared, +mutable state_. -By _shared_, we mean that a variable could be accessed by multiple threads; by _mutable_, we mean that its value could change during its lifetime. We may talk about thread safety as if it were about _code_, but what we are really trying to do is protect _data_ from uncontrolled concurrent access. +By _shared_, we mean that a variable could be accessed by multiple threads; by _mutable_, we mean that its value could +change during its lifetime. We may talk about thread safety as if it were about _code_, but what we are really trying +to do is protect _data_ from uncontrolled concurrent access. -Whenever more than one thread accesses a given state variable, and one of them might write to it, they all must coordinate their access to it using synchronization. +Whenever more than one thread accesses a given state variable, and one of them might write to it, they all must +coordinate their access to it using synchronization. -If multiple threads access the same mutable state variable without appropriate synchronization, _your program is broken_. There are three ways to fix it: +If multiple threads access the same mutable state variable without appropriate synchronization, _your program is +broken_. There are three ways to fix it: * _Don’t share_ the state variable across threads; * Make the state variable _immutable_; or @@ -14,13 +19,17 @@ If multiple threads access the same mutable state variable without appropriate s It is far easier to design a class to be thread-safe than to retrofit it for thread safety later. -When designing thread-safe classes, good object-oriented techniques—encapsulation, immutability, and clear specification of invariants—are your best friends. +When designing thread-safe classes, good object-oriented techniques—encapsulation, immutability, and clear +specification of invariants—are your best friends. ## 2.1 What is thread safety? -A class is _thread-safe_ if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code. +A class is _thread-safe_ if it behaves correctly when accessed from multiple threads, regardless of the scheduling +or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization +or other coordination on the part of the calling code. -No set of operations performed sequentially or concurrently on instances of a thread-safe class can cause an instance to be in an invalid state. +No set of operations performed sequentially or concurrently on instances of a thread-safe class can cause an instance +to be in an invalid state. Thread-safe classes encapsulate any needed synchronization so that clients need not provide their own. @@ -30,21 +39,38 @@ Stateless objects are always thread-safe. ## 2.2 Atomicity -The possibility of incorrect results in the presence of unlucky timing is so important in concurrent programming that it has a name: a _race condition_. +The possibility of incorrect results in the presence of unlucky timing is so important in concurrent programming that +it has a name: a _race condition_. -
race condition or data race? The term _race condition_ is often confused with the related term _data race_, which arises when synchronization is not used to coordinate all access to a shared nonfinal field. You risk a data race whenever a thread writes a variable that might next be read by another thread or reads a variable that might have last been written by another thread if both threads do not use synchronization; code with data races has no useful defined semantics under the Java Memory Model. Not all race conditions are data races, and not all data races are race conditions, but they both can cause concurrent programs to fail in unpredictable ways.
+
race condition or data race? The term _race condition_ is often confused with the related +term _data race_, which arises when synchronization is not used to coordinate all access to a shared non-final field. +You risk a data race whenever a thread writes a variable that might next be read by another thread or reads a variable +that might have last been written by another thread if both threads do not use synchronization; code with data races +has no useful defined semantics under the Java Memory Model. Not all race conditions are data races, and not all data +races are race conditions, but they both can cause concurrent programs to fail in unpredictable ways.
### 2.2.1 Race conditions -The most common type of race condition is _check-then-act_, where a potentially stale observation is used to make a decision on what to do next. +The most common type of race condition is _check-then-act_, where a potentially stale observation is used to make a +decision on what to do next. -Using a potentially stale observation to make a decision or perform a computation is what characterizes most race conditions. This type of race condition is called _check-then-act_: you observe something to be true (file X doesn’t exist) and then take action based on that observation (create X); but in fact the observation could have become invalid between the time you observed it and the time you acted on it (someone else created X in the meantime), causing a problem (unexpected exception, overwritten data, file corruption). +Using a potentially stale observation to make a decision or perform a computation is what characterizes most race +conditions. This type of race condition is called _check-then-act_: you observe something to be true (file X doesn't +exist) and then take action based on that observation (create X); but in fact the observation could have become +invalid between the time you observed it and the time you acted on it (someone else created X in the meantime), +causing a problem (unexpected exception, overwritten data, file corruption). ### 2.2.2 Example: race conditions in lazy initialization A common idiom that uses check-then-act is _lazy initialization_. -The following snippet has race conditions (**don't do this!**) that can undermine its correctness. Say that threads **A** and **B** execute `getInstance` at the same time. **A** sees that instance is `null` , and instantiates a new `ExpensiveObject`. **B** also checks if instance is `null` . Whether instance is `null` at this point depends unpredictably on timing, including the vagaries of scheduling and how long **A** takes to instantiate the `ExpensiveObject` and set the instance field. If instance is `null` when **B** examines it, the two callers to `getInstance` may receive two different results, even though `getInstance` is always supposed to return the same instance. +The following snippet has race conditions (**don't do this!**) that can undermine its correctness. Say that threads +**A** and **B** execute `getInstance` at the same time. **A** sees that instance is `null` , and instantiates a new +`ExpensiveObject`. **B** also checks if instance is `null` . Whether instance is `null` at this point depends +unpredictably on timing, including the vagaries of scheduling and how long **A** takes to instantiate the +`ExpensiveObject` and set the instance field. If instance is `null` when **B** examines it, the two callers to +`getInstance` may receive two different results, even though `getInstance` is always supposed to return +the same instance. ```java @NotThreadSafe @@ -63,32 +89,41 @@ public class LazyInitRace { ### 2.2.3 Compound actions -Operations A and B are _atomic_ with respect to each other if, from the perspective of a thread executing A, when another thread executes B, either all of B has executed or none of it has. An _atomic_ operation is one that is atomic with respect to all operations, including itself, that operate on the same state. +Operations A and B are _atomic_ with respect to each other if, from the perspective of a thread executing A, +when another thread executes B, either all of B has executed or none of it has. An _atomic_ operation is one that +is atomic with respect to all operations, including itself, that operate on the same state. -We refer collectively to check-then-act and read-modify-write sequences as _compound actions_: sequences of operations that must be executed atomically in order to remain thread-safe. +We refer collectively to check-then-act and read-modify-write sequences as _compound actions_: sequences of +operations that must be executed atomically in order to remain thread-safe. When a single element of state is added to a stateless class, the resulting class will be thread-safe if the state is entirely managed by a thread-safe object. -Where practical, use existing thread-safe objects, like `AtomicLong`, to manage your class’s state. It is simpler to reason about the possible states and state transitions for existing thread-safe objects than it is for arbitrary state variables, and this makes it easier to maintain and verify thread safety. +Where practical, use existing thread-safe objects, like `AtomicLong`, to manage your class’s state. It is simpler +to reason about the possible states and state transitions for existing thread-safe objects than it is for arbitrary +state variables, and this makes it easier to maintain and verify thread safety. ## 2.3 Locking -When multiple variables participate in an invariant, they are not _independent_: the value of one constrains the allowed value(s) of the others. Thus when updating one, you must update the others in the same atomic operation. +When multiple variables participate in an invariant, they are not _independent_: the value of one constrains the +allowed value(s) of the others. Thus, when updating one, you must update the others _in the same atomic operation_. To preserve state consistency, update related state variables in a single atomic operation. ### 2.3.1 Intrinsic locks -Java provides a built-in locking mechanism for enforcing atomicity: the _synchronized_ block. Every Java object can implicitly act as a lock for purposes of synchronization; these built-in locks are called _intrinsic locks_ or _monitor locks_. +Java provides a built-in locking mechanism for enforcing atomicity: the _synchronized_ block. Every Java object can +implicitly act as a lock for purposes of synchronization; these built-in locks are called _intrinsic locks_ or +_monitor locks_. -Intrinsic locks in Java act as _mutexes_ (or mutual exclusion locks), which means that at most one thread may own the lock. +Intrinsic locks in Java act as _mutexes_ (or mutual exclusion locks), which means that at most one thread may own +the lock. ### 2.3.2 Reentrancy Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis. -Iintrinsic locks are _reentrant_, if a thread tries to acquire a lock that it already holds, the request succeeds. +Intrinsic locks are _reentrant_, if a thread tries to acquire a lock that it already holds, the request succeeds. ## 2.4 Guarding state with locks @@ -98,16 +133,20 @@ If synchronization is used to coordinate access to a variable, it is needed _eve When using locks to coordinate access to a variable, the _same_ lock must be used wherever that variable is accessed. -For each mutable state variable that may be accessed by more than one thread, _all_ accesses to that variable must be performed with the _same_ lock held. In this case, we say that the variable is _guarded by_ that lock. +For each mutable state variable that may be accessed by more than one thread, _all_ accesses to that variable must +be performed with the _same_ lock held. In this case, we say that the variable is _guarded by_ that lock. Every shared, mutable variable should be guarded by exactly one lock. Make it clear to maintainers which lock that is. -For every invariant that involves more than one variable, _all_ the variables involved in that invariant must be guarded by the _same_ lock. +For every invariant that involves more than one variable, _all_ the variables involved in that invariant must be +guarded by the _same_ lock. ## 2.5 Liveness and performance Acquiring and releasing a lock has some overhead, so it is undesirable to break down synchronized blocks _too_ far. -There is frequently a tension between simplicity and performance. When implementing a synchronization policy, resist the temptation to prematurely sacrifice simplicity (potentially compromising safety) for the sake of performance. +There is frequently a tension between simplicity and performance. When implementing a synchronization policy, resist +the temptation to prematurely sacrifice simplicity (potentially compromising safety) for the sake of performance. -Avoid holding locks during lengthy computations or operations at risk of not completing quickly such as network or console I/O. +Avoid holding locks during lengthy computations or operations at risk of not completing quickly such as network +or console I/O. diff --git a/JavaConcurrencyInPractice/Chapter03/README.md b/JavaConcurrencyInPractice/Chapter03/README.md index 707cc7d0..31e3339b 100644 --- a/JavaConcurrencyInPractice/Chapter03/README.md +++ b/JavaConcurrencyInPractice/Chapter03/README.md @@ -2,62 +2,79 @@ ## 3.1 Visibility -In the absence of synchronization, the compiler, processor, and runtime can do some downright weird things to the order in which operations appear to execute. Attempts to reason about the order in which memory actions “must” happen in insufficiently synchronized multithreaded programs will almost certainly be incorrect. +In the absence of synchronization, the compiler, processor, and runtime can do some downright weird things to the order +in which operations appear to execute. Attempts to reason about the order in which memory actions “must” happen +in insufficiently synchronized multithreaded programs will almost certainly be incorrect. Always use the proper synchronization whenever data is shared across threads. ### 3.1.1 Stale data -Stale data can cause serious and confusing failures such as unexpected exceptions, corrupted data structures, inaccurate computations, and infinite loops. +Stale data can cause serious and confusing failures such as unexpected exceptions, corrupted data structures, +inaccurate computations, and infinite loops. ### 3.1.2 Nonatomic 64-bit operations -Even if you don’t care about stale values, it is not safe to use shared mutable `long` and `double` variables in multithreaded programs unless they are declared `volatile` or guarded by a lock. +Even if you don’t care about stale values, it is not safe to use shared mutable `long` and `double` variables in +multithreaded programs unless they are declared `volatile` or guarded by a lock. ### 3.1.3 Locking and visibility -Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock. +Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the +most up-to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock. ### 3.1.4 Volatile variables -When a field is declared `volatile`, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread. +When a field is declared `volatile`, the compiler and runtime are put on notice that this variable is shared and that +operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers +or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most +recent write by any thread. -Use `volatile` variables only when they simplify implementing and verifying your synchronization policy; avoid using volatile variables when veryfing correctness would require subtle reasoning about visibility. Good uses of `volatile` variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an important lifecycle event (such as initialization or shutdown) has occurred. +Use `volatile` variables only when they simplify implementing and verifying your synchronization policy; avoid +using volatile variables when veryfing correctness would require subtle reasoning about visibility. Good uses of +`volatile` variables include ensuring the visibility of their own state, that of the object they refer to, or +indicating that an important lifecycle event (such as initialization or shutdown) has occurred. Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility. You can use volatile variables only when all the following criteria are met: -* Writes to the variable do not depend on its current value, or you can ensure hat only a single thread ever updates the value; +* Writes to the variable do not depend on its current value, or you can ensure hat only a single thread ever + updates the value; * The variable does not participate in invariants with other state variables; and * ocking is not required for any other reason while the variable is being accessed. ## 3.2 Publication and escape -_Publishing_ an object means making it available to code outside of its current scope, such as by storing a reference to it where other code can find it, returning it from a nonprivate method, or passing it to a method in another class. +_Publishing_ an object means making it available to code outside of its current scope, such as by storing a reference +to it where other code can find it, returning it from a nonprivate method, or passing it to a method in another class. An object that is published when it should not have been is said to have _escaped_. Publishing one object may indirectly publish others. -Any object that is reachable from a published object by following some chain of nonprivate field references and method calls has also +Any object that is reachable from a published object by following some chain of nonprivate field references and method +calls has also been published. -From the perspective of a class `C`, an alien method is one whose behavior is not fully specified by `C`. This includes methods in other classes as well as overrideable methods (neither `private` nor `final`) in `C` itself. Passing an object to an alien method must also be considered publishing that object. Since you can’t know what code will actually be invoked, you don’t know that the alien method won’t publish the object or retain a reference to it that might later be used from another thread. +From the perspective of a class `C`, an alien method is one whose behavior is not fully specified by `C`. This +includes methods in other classes as well as overrideable methods (neither `private` nor `final`) in `C` itself. +Passing an object to an alien method must also be considered publishing that object. Since you can’t know what code +will actually be invoked, you don’t know that the alien method won’t publish the object or retain a reference to it +that might later be used from another thread. -An object or its internal state is also published when an inner class instance is pusblished, because the inner class instances contain a hidden reference to the enclosing instance. i.e.: +An object or its internal state is also published when an inner class instance is pusblished, because the inner +class instances contain a hidden reference to the enclosing instance. i.e.: ```java public class ThisEscape { - public ThisEscape(EventSource source) { - source.registerListener( - new EventListener() { - public void onEvent(Event e) { - doSomething(e); - } - } - ); - } + public ThisEscape(EventSource source) { + source.registerListener(new EventListener() { + public void onEvent(Event e) { + doSomething(e); + } + }); + } } ``` @@ -67,46 +84,55 @@ Do not allow the `this` reference to escape during construction. i.e.: ```java public class SafeListener { - private final EventListener listener; - - private SafeListener() { - listener = new EventListener() { - public void onEvent(Event e) { - doSomething(e); - } - }; - } - - public static SafeListener newInstance(EventSource source) { - SafeListener safe = new SafeListener(); - source.registerListener(safe.listener); - return safe; - } + private final EventListener listener; + + private SafeListener() { + listener = new EventListener() { + public void onEvent(Event e) { + doSomething(e); + } + }; + } + + public static SafeListener newInstance(EventSource source) { + SafeListener safe = new SafeListener(); + source.registerListener(safe.listener); + return safe; + } } ``` ## 3.3 Thread confinement -If data is only accessed from a single thread, no synchronization is needed. This technique, _thread confinement_, is one of the -simplest ways to achieve thread safety. +If data is only accessed from a single thread, no synchronization is needed. This technique, _thread confinement_, is +one of the simplest ways to achieve thread safety. -Thread confinement is an element of your program’s design that must be enforced by its implementation. The language and core libraries provide mechanisms that can help in maintaining thread confinement—local variables and the `ThreadLocal` class—but even with these, it is still the programmer’s responsibility to ensure that thread-confined objects do not escape from their intended thread. +Thread confinement is an element of your program’s design that must be enforced by its implementation. The language and +core libraries provide mechanisms that can help in maintaining thread confinement—local variables and the `ThreadLocal` +class—but even with these, it is still the programmer’s responsibility to ensure that thread-confined objects do not +escape from their intended thread. ### 3.3.1 Ad-hoc thread confinement -_Ad-hoc thread confinement_ describes when the responsibility for maintaining thread confinement falls entirely on the implementation. +_Ad-hoc thread confinement_ describes when the responsibility for maintaining thread confinement falls entirely on +the implementation. -Because of its fragility, ad-hoc thread confinement should be used sparingly; if possible, use one of the stronger forms of thread confinment (stack confinement or `ThreadLocal`) instead. +Because of its fragility, ad-hoc thread confinement should be used sparingly; if possible, use one of the stronger +forms of thread confinment (stack confinement or `ThreadLocal`) instead. ### 3.3.2 Stack confinement -_Stack confinement_ is a special case of thread confinement in which an object can only be reached through local variables. +_Stack confinement_ is a special case of thread confinement in which an object can only be reached through local +variables. ### 3.3.3 ThreadLocal -ThreadLocal allows you to associate a per-thread value with a value-holding object and provides `get` and `set` accessor methods that maintain a separate copy of the value for each thread that uses it, so a `get` returns the most recent value passed to `set` _from the currently executing thread_. +ThreadLocal allows you to associate a per-thread value with a value-holding object and provides `get` and `set` +accessor methods that maintain a separate copy of the value for each thread that uses it, so a `get` returns the most +recent value passed to `set` _from the currently executing thread_. -Like global variables, thread-local variables can detract from reusability and introduce hidden couplings among classes, and should therefore be used with care. +Like global variables, thread-local variables can detract from reusability and introduce hidden couplings among +classes, and should therefore be used with care. ## 3.4 Immutability @@ -120,27 +146,34 @@ An object is immutable if: ### 3.4.1 Final fields -Just as it is a good practice to make all fields `private` unless they need greater visibility, it is a good practice to make all fields `final` unless they need to be mutable. +Just as it is a good practice to make all fields `private` unless they need greater visibility, it is a good practice +to make all fields `final` unless they need to be mutable. ### 3.4.2 Example: Using `volatile` to publish immutable objects -Whenever a group of related data items must be acted on atomically, consider creating an immutable holder class for them. Race conditions in accessing or updating multiple related variables can be eliminated by using an immutable object to hold all the variables. +Whenever a group of related data items must be acted on atomically, consider creating an immutable holder class for +them. Race conditions in accessing or updating multiple related variables can be eliminated by using an immutable +object to hold all the variables. ## 3.5 Safe publication ### 3.5.1 Improper publication: when good objects go bad -When synchronization is not used to make an object instance visible to other threads, we say the object was _not properly published_. +When synchronization is not used to make an object instance visible to other threads, we say the object was _not +properly published_. ### 3.5.2 Immutable objects and initialization safety -Because immutable objects are so important, the Java Memory Model offers a special guarantee of _initialization safety_ for sharing immutable objects. +Because immutable objects are so important, the Java Memory Model offers a special guarantee of _initialization +safety_ for sharing immutable objects. -_Immutable_ objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them. +_Immutable_ objects can be used safely by any thread without additional synchronization, even when synchronization +is not used to publish them. ### 3.5.3 Safe publication idioms -To publish an object safely, both the reference to the object and the object’s state must be made visible to other threads at the same time. A properly constructed object can be safely published by: +To publish an object safely, both the reference to the object and the object’s state must be made visible to other +threads at the same time. A properly constructed object can be safely published by: * Initializing an object reference from a static initializer; * Storing a reference to it into a volatile field or AtomicReference; @@ -149,13 +182,17 @@ To publish an object safely, both the reference to the object and the object’s The thread-safe library collections offer the following safe publication guarantees: -* Placing a key or value in a `Hashtable`, `SynchronizedMap`, or `ConcurrentMap` safely publishes it to any thread that retrieves it from the `Map` (whether directly or via an iterator); -* Placing an element in a `Vector`, `CopyOnWriteArrayList`, `CopyOnWriteArraySet`, `SynchronizedList`, or `SynchronizedSet` safely publishes it to any thread that retrieves it from the collection; -* Placing an element on a `BlockingQueue` or a `ConcurrentLinkedQueue` safely publishes it to any thread that retrieves it from the queue. +* Placing a key or value in a `Hashtable`, `SynchronizedMap`, or `ConcurrentMap` safely publishes it to any thread + that retrieves it from the `Map` (whether directly or via an iterator); +* Placing an element in a `Vector`, `CopyOnWriteArrayList`, `CopyOnWriteArraySet`, `SynchronizedList`, or + `SynchronizedSet` safely publishes it to any thread that retrieves it from the collection; +* Placing an element on a `BlockingQueue` or a `ConcurrentLinkedQueue` safely publishes it to any thread that + retrieves it from the queue. ### 3.5.4 Effectively immutable objects -Objects that are not technically immutable, but whose state will not be modified after publication, are called _effectively immutable_. +Objects that are not technically immutable, but whose state will not be modified after publication, are called +_effectively immutable_. Safely published _effectively immutable_ objects can be used safely by any thread without additional synchronization. @@ -173,8 +210,13 @@ The publication requirements for an object depend on its mutability: The most useful policies for using and sharing objects in a concurrent program are: -* **Thread-confined**. A thread-confined object is owned exclusively by and confined to one thread, and can be modified by its owning thread. -* **Shared read-only**. A shared read-only object can be accessed concurrently by multiple threads without additional synchronization, but cannot be modified by any thread. Shared read-only objects include immutable and effectively immutable objects. -* **Shared thread-safe**. A thread-safe object performs synchronization internally, so multiple threads can freely access it through its public interface without further synchronization. +* **Thread-confined**. A thread-confined object is owned exclusively by and confined to one thread, and can be modified + by its owning thread. +* **Shared read-only**. A shared read-only object can be accessed concurrently by multiple threads without additional + synchronization, but cannot be modified by any thread. Shared read-only objects include immutable and effectively + immutable objects. +* **Shared thread-safe**. A thread-safe object performs synchronization internally, so multiple threads can freely + access it through its public interface without further synchronization. -* **Guarded**. A guarded object can be accessed only with a specific lock held. Guarded objects include those that are encapsulated within other thread-safe objects and published objects that are known to be guarded by a specific lock. +* **Guarded**. A guarded object can be accessed only with a specific lock held. Guarded objects include those that are + encapsulated within other thread-safe objects and published objects that are known to be guarded by a specific lock.