Changes for page Concurrency
Last modified by chrisby on 2024/06/02 15:15
Summary
-
Page properties (1 modified, 0 added, 0 removed)
Details
- Page properties
-
- Content
-
... ... @@ -1,3 +1,129 @@ 1 +## Concurrency 2 + 3 +* Objects are abstractions of processing, threads are abstractions of timing. 4 + 5 +### Why concurrency? 6 + 7 +* **Concurrency is a decoupling strategy**. The what is decoupled from the when. 8 +* **Concurrency is can improve the throughput and structure** of an application. 9 + 10 +### Why not concurrency? 11 + 12 +* **Unclean**: It is hard to write clean concurrent code, and it is harder to test and debug. 13 +* **Design Changes**: Concurrency doesn't always improve performance behavior and but it always requires fundamental design changes. 14 +* **Extra Management**: Concurrency demands a certain amount of management effort, which degrades performance behavior and requires additional code. 15 +* **Complexity**: Proper concurrency is complex, even for simple problems. 16 +* **Unreproducible**: Concurrency bugs are usually not reproducible; therefore, they are often written off as one-time occurrences (cosmic rays, glitches, etc.) rather than treated as true defects, as they should be. 17 +* **Side-Effects**: When threads access out-of-sync data, incorrect results may be returned. 18 + 19 +### Principles of Defensive Concurrency Programming 20 + 21 +* **Single-Responsibility Principle** 22 + * **Separation of code**: Changes to concurrent code should not be mixed with changes to the rest of the code. So you should separate the two cleanly. 23 + * **Separation of change**: Concurrent code has special problems that are different, and often more serious, than sequential code. This means that concurrent and sequential code should be changed separately, not within the same commit, or even within the same branch. 24 +* **Principle of Least Privilege**: Limit concurrent code to the resources it actually needs to avoid side effects. Minimize the amount of shared resources. Divide code blocks and resources into smaller blocks to apply more granular, and therefore more restrictive, resource access. 25 +* **Data Copies**: You can sometimes avoid shared resources by either working with copies of data and treating them as read-only objects, or by making multiple copies of data, having multiple threads compute results on them, and merging those results into a single thread. It is often worth creating multiple objects to avoid concurrency problems. 26 +* **Independence**: Threads should be as independent as possible. Threads should not share their data or know anything about each other. Instead, they should prefer to work with their own local variables. Try to break data into independent subsets that can be processed by independent threads, possibly in different processes. 27 + 28 +### Things to learn before working with concurrency 29 + 30 +* Get to know your library 31 + * Use the thread-safe collections provided. 32 + * Use the executor framework to execute disjointed tasks. 33 + * Use non-blocking solutions if possible. 34 + * Multiple library classes are not thread-safe. 35 +* Thread-safe collections 36 + * So you should use ConcurrentHashMap instead of HashMap. 37 + * Author's recommendations: java.util.concurrent, java.util.concurrent.atomic, java.util.concurrent.locks. 38 +* Get to know execution models 39 + * Basic definitions 40 + * Bound Resources 41 + * Mutual Exclusion 42 + * Starvation 43 + * Deadlock 44 + * Livelock 45 + * Thread Pools 46 + * Future 47 + * Also these?? 48 + * Synchronization: General term for techniques that control the access of multiple threads to shared resources. 49 + * Race Condition: A situation where the system's behavior depends on the relative timing of events, often leading to bugs. 50 + * Semaphore: An abstract data type used to control access to a common resource by multiple threads. 51 + * Locks: Mechanisms to ensure that only one thread can access a resource at a time. 52 + * Atomic Operations: Operations that are completed in a single step relative to other threads. 53 + * Thread Safety 54 + * Race Conditions 55 + * Statelessness, Statefulness 56 + * Functional Programming 57 + * Cloning Data to avoid side effects 58 + * Side effects 59 + * Producer-consumer 60 + * Reader Writer 61 + * Philosopher problem → Study algorithms and their application in solutions. 62 + 63 +A few more suggestions from ChatGPT: 64 + 65 + Learning about concurrency algorithms and common concurrency problems is a great way to deepen your understanding of concurrent programming. Here's a list of key algorithms and problems, along with their typical solutions: 66 + Concurrency Algorithms: 67 + 68 + Producer-Consumer: 69 + Problem: How to handle scenarios where one or more threads (producers) are producing data and one or more threads (consumers) are consuming it. 70 + Solution: Use buffers, queues, semaphores, or condition variables to synchronize producers and consumers. 71 + 72 + Readers-Writers: 73 + Problem: How to manage access to a shared resource where some threads (readers) only read data, and others (writers) write data. 74 + Solution: Implement mechanisms to ensure that multiple readers can access the resource simultaneously, but writers have exclusive access. 75 + 76 + Dining Philosophers: 77 + Problem: A classic synchronization problem dealing with resource allocation and avoiding deadlocks. 78 + Solution: Strategies include resource hierarchy, arbitrator, or limiting the number of philosophers. 79 + 80 + Barriers: 81 + Problem: Synchronizing a group of threads to wait until they have all reached a certain point in their execution. 82 + Solution: Use barrier constructs that block threads until all have reached the barrier. 83 + 84 + Concurrency Problems and Solutions: 85 + 86 + Deadlocks: 87 + Problem: Occurs when multiple threads or processes are waiting on each other to release resources, and none of them can proceed. 88 + Solution: Deadlock prevention techniques (like resource ordering), deadlock avoidance (like Banker’s algorithm), and deadlock detection and recovery. 89 + 90 + Race Conditions: 91 + Problem: Occurs when the outcome of a program depends on the relative timing of threads or processes. 92 + Solution: Use mutual exclusion (mutexes), atomic operations, or transactional memory to ensure that only one thread can access the shared resource at a time. 93 + 94 + Livelocks: 95 + Problem: Threads or processes are actively performing concurrent operations, but these operations do not progress the state of the program. 96 + Solution: Careful algorithm design to ensure progress and avoid situations where processes continuously yield to each other. 97 + 98 + Starvation: 99 + Problem: A thread or process does not get the necessary resources to proceed, while others continue to be serviced. 100 + Solution: Implement fair locking mechanisms, priority scheduling, or resource allocation strategies that ensure all processes get a chance to proceed. 101 + 102 + Priority Inversion: 103 + Problem: A lower-priority thread holds a resource needed by a higher-priority thread, leading to the higher-priority thread waiting unexpectedly. 104 + Solution: Priority inheritance protocols where the lower-priority thread temporarily inherits the higher priority. 105 + 106 + Thread Interference: 107 + Problem: When multiple threads are accessing and modifying shared data, causing unexpected results. 108 + Solution: Ensure that critical sections of code that access shared resources are protected using synchronization mechanisms like locks. 109 + 110 +### Watch out for dependencies between synchronized methods 111 + 112 +* Dependencies between synchronized methods in concurrent code cause subtle bugs. 113 +* Avoid applying more than one method to a shared object. If this is not possible, you have three options: 114 + * Client-based locking: the client should lock the server before the first method is called and ensure that the lock includes the code that calls the last method. 115 + * Server-based locking: Create a method in the server that locks the server, calls all methods, and then unlocks the server. Have the client call the new method. 116 + * Adapted Server: Create an intermediate component that performs the lock. This is a variant of server-based locking if the original server cannot be changed. 117 +* Keep synchronized sections small. 118 + * Locks are expensive because they add administrative overhead to delays. On the other hand, critical sections must be protected. 119 + * Critical sections, are parts of the code that are only executed correctly if several threads do not access it at the same time. 120 + * Keep synchronized sections as small as possible. 121 + 122 +### Writing correct shutdown code is difficult 123 + 124 +* You should think about a shutdown as early as possible and get it running as soon as possible. If you wait, it will always take longer. Study the available algorithms because this task is probably harder than you think. 125 + * TODO: Why do I need shutdown code? 126 + 1 1 Some Notes: 2 2 3 3 * When I/O is the bottleneck of your application, more threads will increase the performance in opposite to when CPU is the bottleneck. ... ... @@ -11,22 +11,3 @@ 11 11 * Client-based locking: User has to manually implement locking. This approach error prone and hard to maintain. 12 12 * If there is no access to the server an adapter class can be used instead. Even better would be thread-save collections using extended interfaces. 13 13 * As little synchronized code (`synchronized`) as possible should be used. And if, then only for small, critical code sections. 14 - 15 -### Problems of testing multi-threaded methods 16 - 17 -* Very tricky which is why concurrency should be avoided in the first place. 18 -* In general this requires a lot of iteration which makes it resource intensive. 19 -* The outcome is architecture dependent (OS, hardware) which introduced randomness and make the error detection unreliable. 20 - 21 -### Solution approaches for testing multi-threaded methods 22 - 23 -* Monte-Carlo-Tests 24 - * Write flexible, adaptive tests. 25 - * Repeatedly run them on a test server and randomly vary the test settings. 26 - * If something fails, the code is defect and the applied settings should be logged. 27 - * Do this early to gain tests ASAP for your testing repertoire or CI-server. 28 -* Execute these tests on every platform over a long time to increase the probability that 29 - * the production code is correct or 30 - * the test code is bad. 31 -* Execute the tests on a computer using simulations of application loads when possible. 32 -* There are tools to test thread-based code like ConTest.