From 49dab27c8593c6b3e2b7264cc896d21640577586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 22 May 2024 13:22:01 +0300 Subject: [PATCH] docs: update thread local storage --- thread-local-storage/README.md | 252 ++++++++---------- .../etc/thread-local-storage.urm.png | Bin 0 -> 43613 bytes .../iluwatar/AbstractThreadLocalExample.java | 2 + 3 files changed, 114 insertions(+), 140 deletions(-) create mode 100644 thread-local-storage/etc/thread-local-storage.urm.png diff --git a/thread-local-storage/README.md b/thread-local-storage/README.md index 97506d58c..7d5d4b902 100644 --- a/thread-local-storage/README.md +++ b/thread-local-storage/README.md @@ -1,105 +1,88 @@ --- -title: Thread-local storage +title: Thread Local Storage category: Concurrency language: en tag: -- Data access + - Isolation + - Memory management + - Thread management --- +## Also known as + +* TLS +* Thread-Specific Storage + ## Intent -Provide an ability to have a copy of a variable for each thread, making it thread-safe. +To provide each thread with its own isolated instance of a variable, avoiding shared access and synchronization issues. ## Explanation -During code assembling compiler add _.tdata_ directive, -which means that variables below will store in different places from thread to thread. -This means changing variable in one thread won't affect the same variable in other thread. +Real-world example -**Real world example** +> Imagine a busy restaurant where each waiter has their own personal notepad to take orders from customers. Each waiter's notepad is separate and used only by that specific waiter. This setup ensures that no waiter interferes with another's orders, avoiding confusion and mistakes. In this analogy, the restaurant represents the application, the waiters represent the threads, and the notepads represent thread-local storage, where each thread maintains its own isolated data. -> On constructions each worker has its own shovel. When one of them broke his shovel, -> other still can continue work due to they have own instrument. +In plain words -**In plain words** +> Thread Local Storage provides each thread with its own isolated instance of a variable, eliminating the need for synchronization and avoiding shared access issues. ->Each thread will have its own copy of variable. +Wikipedia says -**Wikipedia says** - ->Thread-local storage (TLS) is a computer programming method that uses static or global memory local to a thread. +> In computer programming, thread-local storage (TLS) is a memory management method that uses static or global memory local to a thread. The concept allows storage of data that appears to be global in a system with separate threads. **Programmatic Example** -To define variable in thread-local storage you just need to put it into Java's ThreadLocal, e.g: +Consider a scenario where threads need to maintain their own state without interfering with each other. We'll demonstrate this with two implementations: + +1. With ThreadLocal: Each thread has its own isolated instance of a variable. +2. Without ThreadLocal: Threads share a single instance of a variable, leading to potential conflicts. + +We start walking through the code from the base class. + +**AbstractThreadLocalExample** + +* Implements `Runnable` and includes `run` method which pauses the thread, prints the current value, and then changes it. +* `getter` and `setter` methods are abstract and will be implemented by subclasses. + ```java -public class Main { - - private ThreadLocal stringThreadLocal = new ThreadLocal<>(); - - public void initialize(String value) { - this.stringThreadLocal.set(value); - } -} -``` - -Below we will contact a variable from two threads at a time to see, why we need it. -Main logic that show's current variable value is imposed in class AbstractThreadLocalExample, two implementations -differs only in the **value store approach**. - -Main class: - -```java -/** - * Class with main per-thread logic. - */ public abstract class AbstractThreadLocalExample implements Runnable { private static final Random RND = new Random(); @Override public void run() { - //Here we stop thread randomly - LockSupport.parkNanos(RND.nextInt(1_000_000_000, 2_000_000_000)); - - System.out.println(getCurrentThreadName() + ", before value changing: " + getter().get()); - setter().accept(RND.nextInt()); + try { + // Pause thread for a random duration + Thread.sleep(RND.nextInt(1000)); + // Print the current value before changing it + System.out.println(getCurrentThreadName() + ", before value changing: " + getter().get()); + // Change the value + setter().accept(RND.nextInt(1000)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } - /** - * Setter for our value. - * - * @return consumer - */ protected abstract Consumer setter(); - - /** - * Getter for our value. - * - * @return supplier - */ protected abstract Supplier getter(); private String getCurrentThreadName() { return Thread.currentThread().getName(); } } - ``` -And two implementations. With ThreadLocal: -```java -/** - * Example of runnable with use of {@link ThreadLocal}. - */ -public class WithThreadLocal extends AbstractThreadLocalExample { - - private ThreadLocal value; +**WithThreadLocal** - public WithThreadLocal(ThreadLocal value) { - this.value = value; - } +* Uses `ThreadLocal` to ensure each thread has its own instance of `value`. + + +```java +public class WithThreadLocal extends AbstractThreadLocalExample { + + private ThreadLocal value = ThreadLocal.withInitial(() -> 0); @Override protected Consumer setter() { @@ -113,18 +96,15 @@ public class WithThreadLocal extends AbstractThreadLocalExample { } ``` -And the class that stores value in one shared for all threads place: +**WithoutThreadLocal** + +* Uses a shared `value` among all threads, demonstrating potential interference between threads. + + ```java -/** - * Example of runnable without usage of {@link ThreadLocal}. - */ public class WithoutThreadLocal extends AbstractThreadLocalExample { - private Integer value; - - public WithoutThreadLocal(Integer value) { - this.value = value; - } + private Integer value = 0; @Override protected Consumer setter() { @@ -138,110 +118,102 @@ public class WithoutThreadLocal extends AbstractThreadLocalExample { } ``` -Guess we want to run these classes. We will construct both implementations and invoke _run_ method. -So, we want to see initial value in console (thanks to System.out.println()). Let's take a look at tests. +**ThreadLocalTest** + +* Tests both implementations by creating two threads for each and verifying their behavior. ```java public class ThreadLocalTest { - private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - private final PrintStream originalOut = System.out; - - @BeforeEach - public void setUpStreams() { - System.setOut(new PrintStream(outContent)); - } - - @AfterEach - public void restoreStreams() { - System.setOut(originalOut); - } - @Test public void withoutThreadLocal() throws InterruptedException { - int initialValue = 1234567890; - - int threadSize = 2; - ExecutorService executor = Executors.newFixedThreadPool(threadSize); - - WithoutThreadLocal threadLocal = new WithoutThreadLocal(initialValue); - for (int i = 0; i < threadSize; i++) { - executor.submit(threadLocal); + ExecutorService executor = Executors.newFixedThreadPool(2); + for (int i = 0; i < 2; i++) { + executor.submit(new WithoutThreadLocal()); } - executor.awaitTermination(3, TimeUnit.SECONDS); - - List lines = outContent.toString().lines().toList(); - //Matches only first finished thread output, the second has changed by first thread value - Assertions.assertFalse(lines.stream() - .allMatch(line -> line.endsWith(String.valueOf(initialValue)))); + executor.shutdown(); + executor.awaitTermination(1, TimeUnit.SECONDS); } @Test public void withThreadLocal() throws InterruptedException { - int initialValue = 1234567890; - - int threadSize = 2; - ExecutorService executor = Executors.newFixedThreadPool(threadSize); - - WithThreadLocal threadLocal = new WithThreadLocal(ThreadLocal.withInitial(() -> initialValue)); - for (int i = 0; i < threadSize; i++) { - executor.submit(threadLocal); + ExecutorService executor = Executors.newFixedThreadPool(2); + for (int i = 0; i < 2; i++) { + executor.submit(new WithThreadLocal()); } - - executor.awaitTermination(3, TimeUnit.SECONDS); - - List lines = outContent.toString().lines().toList(); - Assertions.assertTrue(lines.stream() - .allMatch(line -> line.endsWith(String.valueOf(initialValue)))); + executor.shutdown(); + executor.awaitTermination(1, TimeUnit.SECONDS); } } ``` The output of test named withThreadLocal: + ``` pool-2-thread-2, before value changing: 1234567890 pool-2-thread-1, before value changing: 1234567890 - ``` And the output of withoutThreadLocal: + ``` pool-1-thread-2, before value changing: 1234567890 pool-1-thread-1, before value changing: 848843054 ``` -Where 1234567890 - is our initial value. We see, that in test _withoutThreadLocal_ -thread 2 got out from LockSupport#parkNanos earlier than the first and -change value in shared variable. + +Where 1234567890 is our initial value. We see that in test withoutThreadLocal thread 2 got out from LockSupport#parkNanos earlier than the first and change value in shared variable. + +This example demonstrates how `ThreadLocal` variables provide isolated storage for each thread, preventing interference from other threads, whereas shared variables can lead to unexpected changes and thread interference. ## Class diagram -```mermaid -classDiagram - class ThreadLocal - ThreadLocal : get() - ThreadLocal : initialValue() - ThreadLocal : remove() - ThreadLocal : set(T value) -``` +![Thread Local Storage](./etc/thread-local-storage.urm.png "Thread Local Storage") ## Applicability -Use ThreadLocal when: - -- You need to run singleton with state in multiple threads -- You need to use not thread-safe classes in concurrency program +* Use when you need to avoid synchronization for performance reasons by providing each thread with its own instance of a variable. +* Useful in scenarios where threads need to maintain state information independently of other threads. +* Suitable for managing per-thread lifecycle states in web servers or handling thread-local configuration in multithreaded applications. ## Tutorials -- [Baeldung](https://www.baeldung.com/java-threadlocal) + +* [An Introduction to ThreadLocal in Java - Baeldung](https://www.baeldung.com/java-threadlocal) ## Known uses -- In java.lang.Thread during thread initialization -- In java.net.URL to prevent recursive provider lookups -- In org.junit.runners.BlockJUnit4ClassRunner to contain current rule -- In org.springframework:spring-web to store request context -- In org.apache.util.net.Nio2Endpoint to allow detecting if a completion handler completes inline -- In io.micrometer to avoid problems with not thread-safe NumberFormat + +* Java ThreadLocal class, commonly used to manage user sessions in web applications. +* Database connections, where each thread gets its own connection instance. +* Locale settings in internationalized applications to ensure thread-specific locale information. +* In java.lang.Thread during thread initialization +* In java.net.URL to prevent recursive provider lookups +* In org.junit.runners.BlockJUnit4ClassRunner to contain current rule +* In org.springframework:spring-web to store request context +* In org.apache.util.net.Nio2Endpoint to allow detecting if a completion handler completes inline +* In io.micrometer to avoid problems with not thread-safe NumberFormat + +## Consequences + +Benefits: + +* Eliminates the need for synchronization, which can improve performance in multithreaded environments. +* Simplifies design by avoiding complex synchronization mechanisms. +* Each thread has its own dedicated storage, reducing contention. + +Trade-offs: + +* Increased memory usage due to multiple instances of the variable. +* Potential for memory leaks if thread-local variables are not properly managed, especially in long-running applications or thread pools. +* Debugging can be more complex due to thread-specific storage behavior. + +## Related Patterns + +* [Singleton](https://java-design-patterns.com/patterns/singleton/): Both patterns ensure a unique instance of a variable, but Thread Local Storage ensures one per thread rather than one per application. +* [Flyweight](https://java-design-patterns.com/patterns/flyweight/): While Flyweight shares instances to minimize memory usage, Thread Local Storage creates separate instances for each thread. ## Credits -- [Usage cases](https://chao-tic.github.io/blog/2018/12/25/tls) -- [Implementation in Linux](https://uclibc.org/docs/tls.pdf) \ No newline at end of file + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Java Concurrency in Practice](https://amzn.to/4aRMruW) +* [A Deep dive into (implicit) Thread Local Storage - Chao-tic](https://chao-tic.github.io/blog/2018/12/25/tls) +* [ELF Handling for Thread-Local Storage - Red Hat Inc.](https://uclibc.org/docs/tls.pdf) diff --git a/thread-local-storage/etc/thread-local-storage.urm.png b/thread-local-storage/etc/thread-local-storage.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..f090fbd4a7a52dd901f6621837e10bb7c448fb40 GIT binary patch literal 43613 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≠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

w*#CNRAD{+Q1Nm6fg)=^BD zL*s%c^M|4`U+#mu+?q}FuPhSfs7pl_RHW_8ety4iX z)YMxb5JW5-E|@UwuDH7w5nl)dLK~nhT8KD3nhmdCPlMp&J9$k_U7a}Xc3d8`v{o-# z<~j`6>dqqj1kx_ebPr$_^w8nu@mKg&gW5YVN3>`}wdL|Nf`meYzE(T|$Z`38 zz{UQ`igu@-GCbl9M|*HNiPrioiqHdK_z7L*i#i`5XDr3n`|Hz$}2-x zu=%(|$_7)Nt`711F7%Oba}K2M)-O>Od4N>FcXCk{d3`N^mz|SC6uI5SXlE%;R|@vWp1pxC6iasjN2q$xL(Wo}8pjS;6ZvOd zA_9hE01+3ye~Yp$!#?(4)2AxvTh!j^RuTC}`E%UOO(GaW-x_i7e3}}qP{`hWV9SdU ztk=UqL^vf_?ez16fk7F7>4c1@H%!gXdhdsVo<{56qu{5c+)*?1 zsC59OJZqudF}|M$G;Cv{56pz1gRHpnkcjoFQi;eKj+sNBJ|)9_($K@hgPRt!+7<;g zWg{++MVK3DS5EpajU+X%6$alHIBt<@FEviokuKe>{AhLa)0LaUR&6-<#jSl;1v#nb zsNJ6?>T@ZLv0k`_iryQ{f{`*N0iHR^Vh}pM(A^MrIfiX7Ee9}4Mf2pGo15x-s!LT= zJjW`}oUAA;=Jnjhx|?3>Gel5E&s{!kJioh~-_frcf)P4__f(E(JSUKXq<>aPUHcDh z4V7DOJ=kDR!^oj*CjwXO;C;v;VJ5gPhhXh*%)noRHu6lx%&{m#SR8Gjr5(8oQpvH{ zd*@BCy;Hhz^sRY~MbO^c1|^_Jo_!WwJ;h+-g*Lf9o0dG^vLx z$xcs%E4>&&qbJ;@r|j~v#~0>>4563LeXX&1-WYr(orlPTKbDD?ERu%dHK?doJkI1D z9Qd%k`(esCMI1-5Rs(z6h)PWjoYd*tX@4uGTyBFX$H6yJCj!UeN=2V-d{EHE z;5<+5!v*H42$(Ji(qWxn+P{l=ud?2S)fK;r3vi~uS@+Zq&z3^4HUi8PF)iN;`>zAu zF9wH(MEO`RFx|F$nf@6kC^J*cSS*w{*?&8CjGg6LM#feameKxx`K@vDl2PPVs`8440Nvih4p_GSkGRr;oR*Ss4YImUAN0sTznqP@9!cjyA8_mYe9Xj zSr&+K0zhNd1;ovhhTVP*5if60edC$DJU5|-eDdsw`)b43<#EuGok!cd9ajpg}|hI_LH9P z6nK&>x{1k&KSfy6%e?}IZ%vASYCSaFXUOX2={ahCT}VJ+YI>T%e|!$@Pr zN$n|Vhtz|q7w3;v@`=oqWU~fn+~eNcwM-mgeXfn8tWPF7H9vpO!(+%itK`XgqX)RV zNtjyY{Rm@lnnS1@2YA4=TCsPg5*C(_>$9@5cBd{Ld^I;j0>^JyO1%jP&3h8o97r@w zk(W0vth_%nE{LWN#x6ithYy|KyO)e7cHZ#lf-Sq}X0_rwU5@DfMeOW3S?$a2v9snl z)8=;EZh(NsadE<&;3|d8P9>!$kiD`9BmV>UplfC!^ID>{fhs#6VR>o?72|0HFIXLc ztU>EdproXPU?|>Ke-3xDJV)}6SAW*5LPLCD^OoTJ-PjHgx*ODv|FQ51-cA*~oksi5zsJ{9b*}#>{Z)<=KgK+~ z0c&rI5ML_Q;M*anTSD1jA||M&i}rh^p5QS;A2dZw99d}CB~XZ@F_wZnCh zV-@quQb3kwy+I&ncKiL=QFUPO_+QV#TMsfMad9GZpna8dN%;4Nr17l(uV)bd%*wdf z>Z007a@n}VLjPNaLQGMezRvW16_8 literal 0 HcmV?d00001 diff --git a/thread-local-storage/src/main/java/com/iluwatar/AbstractThreadLocalExample.java b/thread-local-storage/src/main/java/com/iluwatar/AbstractThreadLocalExample.java index 3d495a61e..35726b37f 100644 --- a/thread-local-storage/src/main/java/com/iluwatar/AbstractThreadLocalExample.java +++ b/thread-local-storage/src/main/java/com/iluwatar/AbstractThreadLocalExample.java @@ -28,10 +28,12 @@ import java.security.SecureRandom; import java.util.concurrent.locks.LockSupport; import java.util.function.Consumer; import java.util.function.Supplier; +import lombok.extern.slf4j.Slf4j; /** * Class with main logic. */ +@Slf4j public abstract class AbstractThreadLocalExample implements Runnable { private static final SecureRandom RND = new SecureRandom();