├── .github └── workflows │ ├── all_url_check.yml │ └── gradle.yml ├── .gitignore ├── .lycheeignore ├── LICENSE ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── AbstractExecutorService.png ├── AbstractExecutorService1.png ├── AbstractOwnableSynchronizer.png ├── AbstractQueue.png ├── Atomics.png ├── BlockingQueue.png ├── CompletionService.png ├── ConcurrentLinkedQueue.png ├── ConcurrentMap.png ├── CopyOnWriteArrayList.png ├── Executor.png ├── Future.png ├── Locks.png ├── Synchronizers.png └── structure.jpeg ├── settings.gradle └── src ├── main └── java │ └── org │ └── alxkm │ ├── antipatterns │ ├── busywaiting │ │ ├── BusyWaitingExample.java │ │ └── BusyWaitingResolution.java │ ├── deadlock │ │ ├── DeadlockExample.java │ │ └── DeadlockResolutionExample.java │ ├── doublechecklocking │ │ ├── Singleton.java │ │ ├── SingletonInitializationOnDemand.java │ │ └── SingletonWithVolatile.java │ ├── excessivesynchronization │ │ ├── AtomicCounter.java │ │ ├── ExcessiveSyncCounter.java │ │ └── OptimizedCounter.java │ ├── forgottensynchronization │ │ ├── CounterExample.java │ │ ├── CounterReentrantLockResolution.java │ │ └── CounterSynchronized.java │ ├── ignoringinterruptedexception │ │ ├── IgnoringInterruptedException.java │ │ ├── PropagatingInterruptedException.java │ │ └── ProperlyHandlingInterruptedException.java │ ├── improperuseofthreadlocal │ │ ├── ThreadLocalCleanupExample.java │ │ ├── ThreadLocalExample.java │ │ └── ThreadLocalWithResourceExample.java │ ├── lackofthreadsafetyinsingletons │ │ ├── DoubleCheckedLockingSingleton.java │ │ ├── HolderSingleton.java │ │ ├── SafeSingleton.java │ │ └── UnsafeSingleton.java │ ├── lockcontention │ │ ├── LockContentionExample.java │ │ ├── LockContentionResolution.java │ │ └── StampedLockExample.java │ ├── nonatomiccompoundactions │ │ ├── AtomicCompoundActionsExample.java │ │ ├── AtomicIntegerExample.java │ │ └── NonAtomicCompoundActionsExample.java │ ├── racecondition │ │ ├── AccountAmount.java │ │ └── AccountExample.java │ ├── startingthreadinconstructor │ │ ├── ThreadInConstructor.java │ │ ├── ThreadStartedOutsideConstructor.java │ │ └── ThreadUsingFactory.java │ ├── threadleakage │ │ ├── ThreadLeakageExample.java │ │ └── ThreadLeakageResolution.java │ ├── threadsinsteadoftasks │ │ ├── CompletableFutureExample.java │ │ ├── DirectThreadManagement.java │ │ └── ExecutorFrameworkExample.java │ └── usingthreadsafecollectionsincorrectly │ │ ├── BaseListUsage.java │ │ ├── CorrectUsage.java │ │ ├── IncorrectUsage.java │ │ ├── OptimizedUsage.java │ │ └── UsageExample.java │ └── patterns │ ├── activeobject │ └── ActiveObject.java │ ├── atomics │ ├── AtomicExample.java │ ├── AtomicIntegerFieldUpdaterExample.java │ ├── AtomicLongFieldUpdaterExample.java │ ├── AtomicMarkableReferenceExample.java │ ├── AtomicReferenceArrayExample.java │ ├── AtomicReferenceExample.java │ ├── AtomicReferenceFieldUpdaterExample.java │ └── AtomicStampedReferenceExample.java │ ├── balking │ └── BalkingPatternExample.java │ ├── collections │ ├── BlockingQueueSimpleExample.java │ ├── ConcurrentHashMapExample.java │ ├── ConcurrentSkipListMapExample.java │ ├── ConcurrentSkipListSetExample.java │ └── CopyOnWriteArrayListExample.java │ ├── doublechecklocking │ └── DoubleCheckedLockingSingleton.java │ ├── executors │ ├── AbstractExecutorServiceExample.java │ ├── CompletionServiceExample.java │ ├── ExecutorServiceExample.java │ ├── ExecutorsExample.java │ ├── ScheduledThreadPoolExecutorExample.java │ ├── ThreadPoolExample.java │ └── ThreadPoolExecutorExample.java │ ├── forkjoinpool │ ├── ForkJoinMergeSort.java │ └── ForkJoinPoolExample.java │ ├── future │ └── FutureExample.java │ ├── guardedsuspension │ └── GuardedSuspensionExample.java │ ├── immutable │ └── Immutable.java │ ├── locks │ ├── AbstractOwnableSynchronizerExample.java │ ├── AbstractQueuedLongSynchronizerExample.java │ ├── AbstractQueuedSynchronizerExample.java │ ├── LockSupportExample.java │ ├── ReadWriteLockExample.java │ ├── ReentrantReadWriteLockCounter.java │ └── ReentrantReadWriteLockCounterExample.java │ ├── monitorobject │ └── MonitorObject.java │ ├── multithreadedcontext │ └── MultithreadedContext.java │ ├── mutex │ └── MutexExample.java │ ├── oddevenprinter │ ├── OddEvenPrinter.java │ └── OddEvenPrinterExample.java │ ├── philosopher │ ├── PhilosopherWithLock.java │ └── PhilosopherWithSemaphore.java │ ├── queue │ ├── ArrayBlockingQueueExample.java │ ├── ConcurrentLinkedDequeExample.java │ ├── ConcurrentLinkedQueueExample.java │ ├── CustomBlockingQueue.java │ └── ProducerConsumerBlockingQueueExample.java │ ├── reactor │ └── Reactor.java │ ├── reentrantlock │ ├── ReentrantLockCounter.java │ └── ReentrantLockExample.java │ ├── scheduler │ └── Scheduler.java │ ├── semaphore │ └── SemaphoreExample.java │ ├── singleton │ └── Singleton.java │ ├── synchronizers │ ├── Barrier.java │ ├── BarrierExample.java │ ├── CountDownLatchExample.java │ ├── ExchangerExample.java │ ├── PhaserExample.java │ └── SemaphorePrintQueueExample.java │ ├── threadlocal │ └── ThreadLocalExample.java │ ├── threadsafelazyinitialization │ └── LazyInitialization.java │ └── twophasetermination │ └── TwoPhaseTermination.java └── test └── java └── org └── alxkm └── patterns ├── activeobjects └── ActiveObjectTest.java ├── atomics └── AtomicExampleTest.java ├── balking └── BalkingPatternExampleTest.java ├── collections ├── ConcurrentHashMapExampleTest.java ├── ConcurrentSkipListSetExampleTest.java └── CopyOnWriteArrayListExampleTest.java ├── doublechecklocking └── DoubleCheckedLockingSingletonTest.java ├── executors ├── CompletionServiceExampleTest.java └── ThreadPoolExampleTest.java ├── future └── FutureExampleTest.java ├── guardedsuspension └── GuardedSuspensionExampleTest.java ├── immutable └── ImmutableTest.java ├── monitorobject └── MonitorObjectTest.java ├── mutex └── MutexExampleTest.java ├── oddevenprinter └── OddEvenPrinterTest.java ├── philosopher ├── PhilosopherWithLockTest.java └── PhilosopherWithSemaphoreTest.java ├── queue ├── ArrayBlockingQueueExampleTest.java └── CustomBlockingQueueTest.java ├── reactor └── ReactorTest.java ├── readwritelock └── ReentrantReadWriteLockCounterTest.java ├── scheduler └── SchedulerTest.java ├── semaphore └── SemaphoreExampleTest.java ├── singleton └── DoubleCheckedLockingSingletonTest.java ├── synchronizers ├── BarrierTest.java ├── CountDownLatchExampleTest.java ├── ExchangerExampleTest.java └── SemaphorePrintQueueExampleTest.java ├── threadlocal └── ThreadLocalExampleTest.java ├── threadsafelazyinitialization └── LazyInitializationTest.java └── twophasetermination └── TwoPhaseTerminationTest.java /.github/workflows/all_url_check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: all_url_check 3 | 4 | 'on': 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | schedule: 11 | - cron: '41 3 * * SUN' 12 | 13 | jobs: 14 | run_lychee: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: run lychee 22 | uses: lycheeverse/lychee-action@v1.10.0 23 | with: 24 | args: > 25 | --no-progress 26 | **/*.java **/*.md 27 | fail: true 28 | ... 29 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time 6 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle 7 | 8 | name: Java CI with Gradle 9 | 10 | on: 11 | push: 12 | branches: [ "main" ] 13 | pull_request: 14 | branches: [ "main" ] 15 | 16 | jobs: 17 | build: 18 | 19 | runs-on: ubuntu-latest 20 | permissions: 21 | contents: read 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up JDK 17 26 | uses: actions/setup-java@v4 27 | with: 28 | java-version: '17' 29 | distribution: 'temurin' 30 | 31 | # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. 32 | # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md 33 | - name: Setup Gradle 34 | uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 35 | 36 | - name: Make gradlew executable 37 | run: chmod +x ./gradlew 38 | 39 | - name: Build with Gradle Wrapper 40 | run: ./gradlew build 41 | 42 | # NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html). 43 | # If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version. 44 | # 45 | # - name: Setup Gradle 46 | # uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 47 | # with: 48 | # gradle-version: '8.5' 49 | # 50 | # - name: Build with Gradle 8.5 51 | # run: gradle build 52 | 53 | dependency-submission: 54 | 55 | runs-on: ubuntu-latest 56 | permissions: 57 | contents: write 58 | 59 | steps: 60 | - uses: actions/checkout@v4 61 | - name: Set up JDK 17 62 | uses: actions/setup-java@v4 63 | with: 64 | java-version: '17' 65 | distribution: 'temurin' 66 | 67 | # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. 68 | # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md 69 | - name: Generate and submit dependency graph 70 | uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | -------------------------------------------------------------------------------- /.lycheeignore: -------------------------------------------------------------------------------- 1 | http://habrahabr.ru/company/luxoft/blog/157273/ 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2024] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'org.alxkm' 6 | version '1.0-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' 14 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' 15 | } 16 | 17 | test { 18 | useJUnitPlatform() 19 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /images/AbstractExecutorService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/AbstractExecutorService.png -------------------------------------------------------------------------------- /images/AbstractExecutorService1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/AbstractExecutorService1.png -------------------------------------------------------------------------------- /images/AbstractOwnableSynchronizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/AbstractOwnableSynchronizer.png -------------------------------------------------------------------------------- /images/AbstractQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/AbstractQueue.png -------------------------------------------------------------------------------- /images/Atomics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/Atomics.png -------------------------------------------------------------------------------- /images/BlockingQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/BlockingQueue.png -------------------------------------------------------------------------------- /images/CompletionService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/CompletionService.png -------------------------------------------------------------------------------- /images/ConcurrentLinkedQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/ConcurrentLinkedQueue.png -------------------------------------------------------------------------------- /images/ConcurrentMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/ConcurrentMap.png -------------------------------------------------------------------------------- /images/CopyOnWriteArrayList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/CopyOnWriteArrayList.png -------------------------------------------------------------------------------- /images/Executor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/Executor.png -------------------------------------------------------------------------------- /images/Future.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/Future.png -------------------------------------------------------------------------------- /images/Locks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/Locks.png -------------------------------------------------------------------------------- /images/Synchronizers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/Synchronizers.png -------------------------------------------------------------------------------- /images/structure.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alxkm/java-concurrency-patterns/0dc7896104e6c16ddf00259157a4a4e187a2a368/images/structure.jpeg -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'concurrency-patterns' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/busywaiting/BusyWaitingExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.busywaiting; 2 | 3 | /** 4 | * Demonstrates busy waiting by continuously checking a condition in a loop without yielding control of the CPU. 5 | */ 6 | public class BusyWaitingExample { 7 | 8 | private volatile boolean flag = false; 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | BusyWaitingExample example = new BusyWaitingExample(); 12 | Thread workerThread = new Thread(example::doWork); 13 | workerThread.start(); 14 | 15 | // Simulate some work in the main thread 16 | Thread.sleep(2000); 17 | 18 | // Set the flag to true to signal the worker thread to proceed 19 | example.flag = true; 20 | 21 | workerThread.join(); 22 | } 23 | 24 | /** 25 | * Continuously checks the flag in a loop, causing busy waiting. 26 | */ 27 | public void doWork() { 28 | while (!flag) { 29 | // Busy wait 30 | } 31 | System.out.println("Flag is set. Proceeding with work..."); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/busywaiting/BusyWaitingResolution.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.busywaiting; 2 | 3 | /** 4 | * Demonstrates the resolution of busy waiting by using the wait() and notify() methods for thread synchronization. 5 | */ 6 | public class BusyWaitingResolution { 7 | 8 | private boolean flag = false; 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | BusyWaitingResolution example = new BusyWaitingResolution(); 12 | Thread workerThread = new Thread(example::doWork); 13 | workerThread.start(); 14 | 15 | // Simulate some work in the main thread 16 | Thread.sleep(2000); 17 | 18 | // Set the flag to true and notify the worker thread to proceed 19 | synchronized (example) { 20 | example.flag = true; 21 | example.notify(); 22 | } 23 | 24 | workerThread.join(); 25 | } 26 | 27 | /** 28 | * Uses the wait() method to avoid busy waiting. 29 | */ 30 | public synchronized void doWork() { 31 | while (!flag) { 32 | try { 33 | // Wait for the flag to be set 34 | wait(); 35 | } catch (InterruptedException e) { 36 | Thread.currentThread().interrupt(); 37 | } 38 | } 39 | System.out.println("Flag is set. Proceeding with work..."); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/deadlock/DeadlockExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.deadlock; 2 | 3 | /** 4 | * Example demonstrating a deadlock situation. 5 | */ 6 | public class DeadlockExample { 7 | private final Object lock1 = new Object(); 8 | private final Object lock2 = new Object(); 9 | 10 | /** 11 | * Main method to run the deadlock example. 12 | * 13 | * @param args command line arguments 14 | */ 15 | public static void main(String[] args) { 16 | DeadlockExample example = new DeadlockExample(); 17 | example.causeDeadlock(); 18 | } 19 | 20 | /** 21 | * Method that creates and starts two threads which will cause a deadlock. 22 | */ 23 | public void causeDeadlock() { 24 | Thread t1 = new Thread(() -> { 25 | synchronized (lock1) { 26 | System.out.println("Thread 1: Holding lock 1..."); 27 | 28 | try { 29 | Thread.sleep(100); 30 | } catch (InterruptedException e) { 31 | Thread.currentThread().interrupt(); 32 | } 33 | System.out.println("Thread 1: Waiting for lock 2..."); 34 | 35 | synchronized (lock2) { 36 | System.out.println("Thread 1: Holding lock 1 & 2..."); 37 | } 38 | } 39 | }); 40 | 41 | Thread t2 = new Thread(() -> { 42 | synchronized (lock2) { 43 | System.out.println("Thread 2: Holding lock 2..."); 44 | 45 | try { 46 | Thread.sleep(100); 47 | } catch (InterruptedException e) { 48 | Thread.currentThread().interrupt(); 49 | } 50 | System.out.println("Thread 2: Waiting for lock 1..."); 51 | 52 | synchronized (lock1) { 53 | System.out.println("Thread 2: Holding lock 1 & 2..."); 54 | } 55 | } 56 | }); 57 | 58 | t1.start(); 59 | t2.start(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/deadlock/DeadlockResolutionExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.deadlock; 2 | 3 | /** 4 | * Example demonstrating the resolution of a deadlock situation. 5 | */ 6 | public class DeadlockResolutionExample { 7 | private final Object lock1 = new Object(); 8 | private final Object lock2 = new Object(); 9 | 10 | /** 11 | * Main method to run the deadlock resolution example. 12 | * 13 | * @param args command line arguments 14 | */ 15 | public static void main(String[] args) { 16 | DeadlockResolutionExample example = new DeadlockResolutionExample(); 17 | example.resolveDeadlock(); 18 | } 19 | 20 | /** 21 | * Method that creates and starts two threads which will avoid deadlock by acquiring locks in the same order. 22 | */ 23 | public void resolveDeadlock() { 24 | Thread t1 = new Thread(() -> { 25 | synchronized (lock1) { 26 | System.out.println("Thread 1: Holding lock 1..."); 27 | 28 | try { 29 | Thread.sleep(100); 30 | } catch (InterruptedException e) { 31 | Thread.currentThread().interrupt(); 32 | } 33 | System.out.println("Thread 1: Waiting for lock 2..."); 34 | 35 | synchronized (lock2) { 36 | System.out.println("Thread 1: Holding lock 1 & 2..."); 37 | } 38 | } 39 | }); 40 | 41 | Thread t2 = new Thread(() -> { 42 | synchronized (lock1) { // Changed the order of acquiring locks 43 | System.out.println("Thread 2: Holding lock 1..."); 44 | 45 | try { 46 | Thread.sleep(100); 47 | } catch (InterruptedException e) { 48 | Thread.currentThread().interrupt(); 49 | } 50 | System.out.println("Thread 2: Waiting for lock 2..."); 51 | 52 | synchronized (lock2) { 53 | System.out.println("Thread 2: Holding lock 1 & 2..."); 54 | } 55 | } 56 | }); 57 | 58 | t1.start(); 59 | t2.start(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/doublechecklocking/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.doublechecklocking; 2 | 3 | 4 | /** 5 | * Double-checked locking is a design pattern used to reduce the overhead of acquiring a lock 6 | * by first testing the locking criterion without actually acquiring the lock. 7 | * However, the original implementation of this pattern was broken in Java before version 5 due to the lack of guaranteed visibility of changes to variables across threads. 8 | *

9 | *

10 | * In this example, the double-checked locking pattern is used to lazily initialize the singleton instance. 11 | * However, this implementation is broken in Java versions before Java 5 due to issues with the Java Memory Model (JMM), 12 | * which could cause the instance variable to appear initialized before it is fully constructed. 13 | */ 14 | public class Singleton { 15 | private static Singleton instance; 16 | 17 | /** 18 | * Private constructor to prevent instantiation. 19 | */ 20 | private Singleton() { 21 | } 22 | 23 | /** 24 | * Returns the singleton instance. 25 | * This implementation of double-checked locking is broken in pre-Java 5 versions. 26 | * 27 | * @return the singleton instance. 28 | */ 29 | public static Singleton getInstance() { 30 | if (instance == null) { // First check (not synchronized) 31 | synchronized ( Singleton.class) { 32 | if (instance == null) { // Second check (synchronized) 33 | instance = new Singleton(); 34 | } 35 | } 36 | } 37 | return instance; 38 | } 39 | 40 | public void showMessage() { 41 | System.out.println("Singleton instance method called."); 42 | } 43 | 44 | public static void main(String[] args) { 45 | Singleton singleton = Singleton.getInstance(); 46 | singleton.showMessage(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/doublechecklocking/SingletonInitializationOnDemand.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.doublechecklocking; 2 | 3 | /** 4 | * Another approach to implement lazy initialization in a thread-safe manner is to use the Initialization-on-Demand Holder idiom, 5 | * which leverages the class loader mechanism to ensure thread safety. 6 | *

7 | *

8 | * In this version, the Holder class is loaded on the first invocation of getInstance(), 9 | * and since class loading is thread-safe, this approach ensures that the singleton instance is created in a thread-safe manner without the need for synchronization or volatile variables. 10 | */ 11 | public class SingletonInitializationOnDemand { 12 | /** 13 | * Private constructor to prevent instantiation. 14 | */ 15 | private SingletonInitializationOnDemand() { 16 | } 17 | 18 | /** 19 | * Static inner class - inner classes are not loaded until they are referenced. 20 | */ 21 | private static class Holder { 22 | private static final SingletonInitializationOnDemand INSTANCE = new SingletonInitializationOnDemand(); 23 | } 24 | 25 | /** 26 | * Returns the singleton instance. 27 | * This implementation uses the Initialization-on-Demand Holder idiom to ensure thread safety. 28 | * 29 | * @return the singleton instance. 30 | */ 31 | public static SingletonInitializationOnDemand getInstance() { 32 | return Holder.INSTANCE; 33 | } 34 | 35 | public void showMessage() { 36 | System.out.println("Singleton instance method called."); 37 | } 38 | 39 | public static void main(String[] args) { 40 | SingletonInitializationOnDemand singleton = SingletonInitializationOnDemand.getInstance(); 41 | singleton.showMessage(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/doublechecklocking/SingletonWithVolatile.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.doublechecklocking; 2 | 3 | /** 4 | * Starting from Java 5, the volatile keyword ensures that changes to a variable are visible to all threads, 5 | * which fixes the double-checked locking pattern. 6 | *

7 | *

8 | * In this revised example, the volatile keyword is used for the instance variable, 9 | * ensuring proper visibility of changes across threads and fixing the broken double-checked locking pattern. 10 | */ 11 | public class SingletonWithVolatile { 12 | private static volatile SingletonWithVolatile instance; 13 | 14 | /** 15 | * Private constructor to prevent instantiation. 16 | */ 17 | private SingletonWithVolatile() { 18 | } 19 | 20 | /** 21 | * Returns the singleton instance. 22 | * This implementation uses volatile keyword to ensure thread safety. 23 | * 24 | * @return the singleton instance. 25 | */ 26 | public static SingletonWithVolatile getInstance() { 27 | if (instance == null) { // First check (not synchronized) 28 | synchronized (Singleton.class) { 29 | if (instance == null) { // Second check (synchronized) 30 | instance = new SingletonWithVolatile(); 31 | } 32 | } 33 | } 34 | return instance; 35 | } 36 | 37 | public void showMessage() { 38 | System.out.println("Singleton instance method called."); 39 | } 40 | 41 | public static void main(String[] args) { 42 | SingletonWithVolatile singleton = SingletonWithVolatile.getInstance(); 43 | singleton.showMessage(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/excessivesynchronization/AtomicCounter.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.excessivesynchronization; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | 6 | /** 7 | * Another approach to resolving excessive synchronization is to use atomic variables, 8 | * which provide thread-safe operations without explicit synchronization. 9 | *

10 | *

11 | * Using AtomicInteger simplifies the code and ensures thread safety without the need for explicit synchronization, providing better performance in highly concurrent scenarios. 12 | **/ 13 | public class AtomicCounter { 14 | private final AtomicInteger count = new AtomicInteger(); 15 | 16 | /** 17 | * Increments the counter by one. 18 | * This method uses AtomicInteger for thread-safe increment operation. 19 | */ 20 | public void increment() { 21 | count.incrementAndGet(); 22 | } 23 | 24 | /** 25 | * Decrements the counter by one. 26 | * This method uses AtomicInteger for thread-safe decrement operation. 27 | */ 28 | public void decrement() { 29 | count.decrementAndGet(); 30 | } 31 | 32 | /** 33 | * Returns the current value of the counter. 34 | * This method uses AtomicInteger for thread-safe read operation. 35 | * 36 | * @return the current count value. 37 | */ 38 | public int getCount() { 39 | return count.get(); 40 | } 41 | 42 | /** 43 | * Main method to demonstrate the usage of AtomicCounter. 44 | */ 45 | public static void main(String[] args) { 46 | AtomicCounter counter = new AtomicCounter(); 47 | 48 | // Print initial count 49 | System.out.println("Initial count: " + counter.getCount()); 50 | 51 | // Increment the counter 52 | counter.increment(); 53 | System.out.println("Count after incrementing: " + counter.getCount()); 54 | 55 | // Decrement the counter 56 | counter.decrement(); 57 | System.out.println("Count after decrementing: " + counter.getCount()); 58 | 59 | // Increment multiple times 60 | counter.increment(); 61 | counter.increment(); 62 | counter.increment(); 63 | System.out.println("Count after incrementing three times: " + counter.getCount()); 64 | 65 | // Decrement multiple times 66 | counter.decrement(); 67 | counter.decrement(); 68 | System.out.println("Count after decrementing two times: " + counter.getCount()); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/forgottensynchronization/CounterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.forgottensynchronization; 2 | 3 | /** 4 | * 5 | * Forgotten synchronization is a common concurrency issue in Java where a method or block of code that should be synchronized is not, 6 | * potentially leading to inconsistent data states or race conditions. Here's an example demonstrating this problem along with a resolution. 7 | * 8 | * 9 | * In this example, the increment method and the getCount method are not synchronized, 10 | * leading to potential race conditions when accessed by multiple threads simultaneously. 11 | * 12 | */ 13 | public class CounterExample { 14 | private int counter = 0; 15 | 16 | /** 17 | * Increments the counter by one. 18 | * This method is not synchronized, leading to potential race conditions. 19 | */ 20 | public void increment() { 21 | counter++; 22 | } 23 | 24 | /** 25 | * Returns the current value of the counter. 26 | * This method is not synchronized, which may result in reading an inconsistent value. 27 | * 28 | * @return the current count value. 29 | */ 30 | public int getCounter() { 31 | return counter; 32 | } 33 | 34 | 35 | public static void main(String[] args) throws InterruptedException { 36 | CounterExample counter = new CounterExample(); 37 | 38 | // Create two threads that both call increment 1000 times 39 | Thread t1 = new Thread(() -> { 40 | for (int i = 0; i < 1000; i++) { 41 | counter.increment(); 42 | } 43 | }); 44 | 45 | Thread t2 = new Thread(() -> { 46 | for (int i = 0; i < 1000; i++) { 47 | counter.increment(); 48 | } 49 | }); 50 | 51 | t1.start(); 52 | t2.start(); 53 | 54 | // Wait for threads to finish 55 | t1.join(); 56 | t2.join(); 57 | 58 | // This will likely print a number less than 2000 due to race conditions 59 | System.out.println("Final Counter Value (without synchronization): " + counter.getCounter()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/forgottensynchronization/CounterReentrantLockResolution.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.forgottensynchronization; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * Instead of using the synchronized keyword, we can use ReentrantLock for more advanced synchronization control. 8 | * 9 | * Using ReentrantLock provides more flexibility and control over the synchronization process, 10 | * including the ability to use tryLock, lockInterruptibly, and other features not available with the synchronized keyword. 11 | */ 12 | public class CounterReentrantLockResolution { 13 | private int count = 0; 14 | private final Lock lock = new ReentrantLock(); 15 | 16 | /** 17 | * Increments the counter by one. 18 | * This method uses a ReentrantLock to prevent race conditions. 19 | */ 20 | public void increment() { 21 | lock.lock(); 22 | try { 23 | count++; 24 | } finally { 25 | lock.unlock(); 26 | } 27 | } 28 | 29 | /** 30 | * Returns the current value of the counter. 31 | * This method uses a ReentrantLock to ensure consistent read operations. 32 | * 33 | * @return the current count value. 34 | */ 35 | public int getCount() { 36 | lock.lock(); 37 | try { 38 | return count; 39 | } finally { 40 | lock.unlock(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/forgottensynchronization/CounterSynchronized.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.forgottensynchronization; 2 | 3 | /** 4 | * 5 | * To resolve this issue, we need to synchronize the methods to ensure that only one thread can access these critical sections at a time. 6 | * 7 | */ 8 | public class CounterSynchronized { 9 | private int counter = 0; 10 | 11 | /** 12 | * Increments the counter by one. 13 | * This method is synchronized to prevent race conditions. 14 | */ 15 | public synchronized void increment() { 16 | counter++; 17 | } 18 | 19 | /** 20 | * Returns the current value of the counter. 21 | * This method is synchronized to ensure consistent read operations. 22 | * 23 | * @return the current count value. 24 | */ 25 | public synchronized int getCounter() { 26 | return counter; 27 | } 28 | 29 | public static void main(String[] args) throws InterruptedException { 30 | CounterSynchronized counter = new CounterSynchronized(); 31 | 32 | // Create two threads that both call increment 1000 times 33 | Thread t1 = new Thread(() -> { 34 | for (int i = 0; i < 1000; i++) { 35 | counter.increment(); 36 | } 37 | }); 38 | 39 | Thread t2 = new Thread(() -> { 40 | for (int i = 0; i < 1000; i++) { 41 | counter.increment(); 42 | } 43 | }); 44 | 45 | t1.start(); 46 | t2.start(); 47 | 48 | // Wait for threads to finish 49 | t1.join(); 50 | t2.join(); 51 | 52 | // This will always print 2000 because of proper synchronization 53 | System.out.println("Final Counter Value (with synchronization): " + counter.getCounter()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/ignoringinterruptedexception/IgnoringInterruptedException.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.ignoringinterruptedexception; 2 | 3 | /** 4 | * Ignoring InterruptedException is a common problem in Java concurrency where threads that are interrupted do not properly handle the interruption, 5 | * leading to issues like thread leaks, unresponsive applications, or improper termination of tasks. Here's an example demonstrating this problem along with a resolution. 6 | * 7 | * In this example, the run method catches InterruptedException but does not handle it appropriately, 8 | * simply ignoring it. This can cause the thread to continue running even when it should stop. 9 | * 10 | */ 11 | public class IgnoringInterruptedException implements Runnable { 12 | /** 13 | * The run method performs a long-running task. 14 | * It ignores InterruptedException, which is a bad practice. 15 | */ 16 | @Override 17 | public void run() { 18 | while (true) { 19 | try { 20 | // Simulating long-running task 21 | Thread.sleep(1000); 22 | System.out.println("Working..."); 23 | } catch (InterruptedException e) { 24 | // Ignoring the interruption, which is bad practice 25 | } 26 | } 27 | } 28 | 29 | public static void main(String[] args) { 30 | Thread thread = new Thread(new IgnoringInterruptedException()); 31 | thread.start(); 32 | 33 | // Interrupt the thread after 3 seconds 34 | try { 35 | Thread.sleep(3000); 36 | } catch (InterruptedException e) { 37 | e.printStackTrace(); 38 | } 39 | thread.interrupt(); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/ignoringinterruptedexception/PropagatingInterruptedException.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.ignoringinterruptedexception; 2 | 3 | /** 4 | * Another approach is to propagate the InterruptedException up the call stack, 5 | * allowing higher-level methods to handle it appropriately. 6 | * 7 | * 8 | * In this version, the loop condition checks for Thread.currentThread().isInterrupted(), 9 | * ensuring that the loop exits when the thread is interrupted. 10 | * The InterruptedException is caught and handled by logging a message and exiting the loop. 11 | * 12 | */ 13 | public class PropagatingInterruptedException implements Runnable { 14 | /** 15 | * The run method performs a long-running task. 16 | * It propagates InterruptedException by declaring it in the method signature. 17 | */ 18 | @Override 19 | public void run() { 20 | try { 21 | while (!Thread.currentThread().isInterrupted()) { 22 | // Simulating long-running task 23 | Thread.sleep(1000); 24 | System.out.println("Working..."); 25 | } 26 | } catch (InterruptedException e) { 27 | System.out.println("Thread was interrupted, stopping."); 28 | } 29 | } 30 | 31 | public static void main(String[] args) { 32 | Thread thread = new Thread(new PropagatingInterruptedException()); 33 | thread.start(); 34 | 35 | // Interrupt the thread after 3 seconds 36 | try { 37 | Thread.sleep(3000); 38 | } catch (InterruptedException e) { 39 | e.printStackTrace(); 40 | } 41 | thread.interrupt(); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/ignoringinterruptedexception/ProperlyHandlingInterruptedException.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.ignoringinterruptedexception; 2 | 3 | /** 4 | * 5 | * To resolve this issue, the thread should properly handle InterruptedException by either propagating the exception or breaking out of the loop. 6 | * 7 | * In this revised example, the run method handles the 8 | * InterruptedException by restoring the interrupt status with Thread.currentThread().interrupt() and breaking out of the loop. 9 | * This ensures that the thread stops running as intended. 10 | * 11 | */ 12 | public class ProperlyHandlingInterruptedException implements Runnable { 13 | /** 14 | * The run method performs a long-running task. 15 | * It handles InterruptedException properly by restoring the interrupt status. 16 | */ 17 | @Override 18 | public void run() { 19 | while (true) { 20 | try { 21 | // Simulating long-running task 22 | Thread.sleep(1000); 23 | System.out.println("Working..."); 24 | } catch (InterruptedException e) { 25 | // Restore the interrupted status 26 | Thread.currentThread().interrupt(); 27 | System.out.println("Thread was interrupted, stopping."); 28 | break; 29 | } 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | Thread thread = new Thread(new ProperlyHandlingInterruptedException()); 35 | thread.start(); 36 | 37 | // Interrupt the thread after 3 seconds 38 | try { 39 | Thread.sleep(3000); 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } 43 | thread.interrupt(); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/improperuseofthreadlocal/ThreadLocalCleanupExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.improperuseofthreadlocal; 2 | 3 | /** 4 | * To avoid memory leaks, ensure that ThreadLocal variables are cleaned up after use by calling the remove method. 5 | *

6 | *

7 | * In this revised example, the removeThreadLocalValue method is called in the finally block to ensure that the ThreadLocal variable is cleaned up after use, preventing memory leaks. 8 | */ 9 | public class ThreadLocalCleanupExample { 10 | private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>(); 11 | 12 | /** 13 | * Sets a value in the ThreadLocal variable. 14 | * 15 | * @param value the value to set. 16 | */ 17 | public void setThreadLocalValue(String value) { 18 | THREAD_LOCAL.set(value); 19 | } 20 | 21 | /** 22 | * Gets the value from the ThreadLocal variable. 23 | * 24 | * @return the value from ThreadLocal. 25 | */ 26 | public String getThreadLocalValue() { 27 | return THREAD_LOCAL.get(); 28 | } 29 | 30 | /** 31 | * Removes the value from the ThreadLocal variable to prevent memory leaks. 32 | */ 33 | public void removeThreadLocalValue() { 34 | THREAD_LOCAL.remove(); 35 | } 36 | 37 | public static void main(String[] args) { 38 | ThreadLocalCleanupExample example = new ThreadLocalCleanupExample(); 39 | 40 | Runnable task = () -> { 41 | try { 42 | example.setThreadLocalValue("ThreadLocal value"); 43 | System.out.println(Thread.currentThread().getName() + ": " + example.getThreadLocalValue()); 44 | // Simulating work 45 | Thread.sleep(1000); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } finally { 49 | // Ensure the ThreadLocal variable is cleaned up 50 | example.removeThreadLocalValue(); 51 | } 52 | }; 53 | 54 | Thread thread1 = new Thread(task); 55 | Thread thread2 = new Thread(task); 56 | 57 | thread1.start(); 58 | thread2.start(); 59 | 60 | try { 61 | thread1.join(); 62 | thread2.join(); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/improperuseofthreadlocal/ThreadLocalExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.improperuseofthreadlocal; 2 | 3 | /** 4 | * 5 | * Using ThreadLocal incorrectly can lead to memory leaks or unexpected behavior. 6 | * ThreadLocal variables are meant to provide thread-specific storage that each thread can independently access, 7 | * but improper usage or not cleaning up properly can cause problems. 8 | *

9 | * In this example, the ThreadLocal variable is used to store and retrieve values specific to each thread. 10 | * However, the values are not removed after usage, which can lead to memory leaks, 11 | * especially in environments where threads are reused, such as in thread pools. 12 | * 13 | */ 14 | public class ThreadLocalExample { 15 | private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>(); 16 | 17 | /** 18 | * Sets a value in the ThreadLocal variable. 19 | * 20 | * @param value the value to set. 21 | */ 22 | public void setThreadLocalValue(String value) { 23 | THREAD_LOCAL.set(value); 24 | } 25 | 26 | /** 27 | * Gets the value from the ThreadLocal variable. 28 | * 29 | * @return the value from ThreadLocal. 30 | */ 31 | public String getThreadLocalValue() { 32 | return THREAD_LOCAL.get(); 33 | } 34 | 35 | public static void main(String[] args) { 36 | ThreadLocalExample example = new ThreadLocalExample(); 37 | 38 | Runnable task = () -> { 39 | example.setThreadLocalValue("ThreadLocal value"); 40 | System.out.println(Thread.currentThread().getName() + ": " + example.getThreadLocalValue()); 41 | // Simulating work 42 | try { 43 | Thread.sleep(1000); 44 | } catch (InterruptedException e) { 45 | e.printStackTrace(); 46 | } 47 | // Not removing the value can cause memory leaks 48 | }; 49 | 50 | Thread thread1 = new Thread(task); 51 | Thread thread2 = new Thread(task); 52 | 53 | thread1.start(); 54 | thread2.start(); 55 | 56 | try { 57 | thread1.join(); 58 | thread2.join(); 59 | } catch (InterruptedException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/improperuseofthreadlocal/ThreadLocalWithResourceExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.improperuseofthreadlocal; 2 | 3 | /** 4 | * Java 7 introduced the AutoCloseable interface and try-with-resources statement, 5 | * which can be adapted for ThreadLocal cleanup using a custom utility class. 6 | *

7 | * In this version, the ThreadLocalCleaner class implements AutoCloseable, allowing it to be used in a try-with-resources statement to ensure ThreadLocal cleanup. 8 | */ 9 | public class ThreadLocalWithResourceExample { 10 | private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>(); 11 | 12 | /** 13 | * Custom class to handle ThreadLocal cleanup using AutoCloseable. 14 | */ 15 | public static class ThreadLocalCleaner implements AutoCloseable { 16 | @Override 17 | public void close() { 18 | THREAD_LOCAL.remove(); 19 | } 20 | } 21 | 22 | /** 23 | * Sets a value in the ThreadLocal variable. 24 | * 25 | * @param value the value to set. 26 | */ 27 | public void setThreadLocalValue(String value) { 28 | THREAD_LOCAL.set(value); 29 | } 30 | 31 | /** 32 | * Gets the value from the ThreadLocal variable. 33 | * 34 | * @return the value from ThreadLocal. 35 | */ 36 | public String getThreadLocalValue() { 37 | return THREAD_LOCAL.get(); 38 | } 39 | 40 | public static void main(String[] args) { 41 | ThreadLocalWithResourceExample example = new ThreadLocalWithResourceExample(); 42 | 43 | Runnable task = () -> { 44 | try (ThreadLocalCleaner cleaner = new ThreadLocalCleaner()) { 45 | example.setThreadLocalValue("ThreadLocal value"); 46 | System.out.println(Thread.currentThread().getName() + ": " + example.getThreadLocalValue()); 47 | // Simulating work 48 | Thread.sleep(1000); 49 | } catch (InterruptedException e) { 50 | e.printStackTrace(); 51 | } 52 | }; 53 | 54 | Thread thread1 = new Thread(task); 55 | Thread thread2 = new Thread(task); 56 | 57 | thread1.start(); 58 | thread2.start(); 59 | 60 | try { 61 | thread1.join(); 62 | thread2.join(); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lackofthreadsafetyinsingletons/DoubleCheckedLockingSingleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lackofthreadsafetyinsingletons; 2 | 3 | /** 4 | * 5 | * Another approach is to use double-checked locking with the volatile keyword to minimize synchronization overhead. 6 | *

7 | * In this version, the volatile keyword ensures visibility of changes to the instance variable across threads, 8 | * while double-checked locking minimizes synchronization overhead. 9 | * 10 | */ 11 | public class DoubleCheckedLockingSingleton { 12 | private static volatile DoubleCheckedLockingSingleton instance; 13 | 14 | /** 15 | * Private constructor to prevent instantiation. 16 | */ 17 | private DoubleCheckedLockingSingleton() { 18 | } 19 | 20 | /** 21 | * Returns the singleton instance using double-checked locking with volatile. 22 | * 23 | * @return the singleton instance. 24 | */ 25 | public static DoubleCheckedLockingSingleton getInstance() { 26 | if (instance == null) { 27 | synchronized (DoubleCheckedLockingSingleton.class) { 28 | if (instance == null) { 29 | instance = new DoubleCheckedLockingSingleton(); 30 | } 31 | } 32 | } 33 | return instance; 34 | } 35 | 36 | public void showMessage() { 37 | System.out.println("DoubleCheckedLockingSingleton instance method called."); 38 | } 39 | 40 | public static void main(String[] args) { 41 | Runnable task = () -> { 42 | DoubleCheckedLockingSingleton singleton = DoubleCheckedLockingSingleton.getInstance(); 43 | singleton.showMessage(); 44 | }; 45 | 46 | Thread thread1 = new Thread(task); 47 | Thread thread2 = new Thread(task); 48 | 49 | thread1.start(); 50 | thread2.start(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lackofthreadsafetyinsingletons/HolderSingleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lackofthreadsafetyinsingletons; 2 | 3 | /** 4 | * 5 | * Alternative Resolution: Initialization-on-Demand Holder Idiom 6 | * Another approach to implement a thread-safe singleton is the Initialization-on-Demand Holder idiom, which leverages the class loader mechanism to ensure thread safety. 7 | *

8 | * In this version, the Holder class is loaded on the first invocation of getInstance(), ensuring thread safety through the class loader mechanism. 9 | * 10 | **/ 11 | public class HolderSingleton { 12 | /** 13 | * Private constructor to prevent instantiation. 14 | */ 15 | private HolderSingleton() { 16 | } 17 | 18 | /** 19 | * Static inner class - inner classes are not loaded until they are referenced. 20 | */ 21 | private static class Holder { 22 | private static final HolderSingleton INSTANCE = new HolderSingleton(); 23 | } 24 | 25 | /** 26 | * Returns the singleton instance. 27 | * This implementation uses the Initialization-on-Demand Holder idiom to ensure thread safety. 28 | * 29 | * @return the singleton instance. 30 | */ 31 | public static HolderSingleton getInstance() { 32 | return Holder.INSTANCE; 33 | } 34 | 35 | public void showMessage() { 36 | System.out.println("HolderSingleton instance method called."); 37 | } 38 | 39 | public static void main(String[] args) { 40 | Runnable task = () -> { 41 | HolderSingleton singleton = HolderSingleton.getInstance(); 42 | singleton.showMessage(); 43 | }; 44 | 45 | Thread thread1 = new Thread(task); 46 | Thread thread2 = new Thread(task); 47 | 48 | thread1.start(); 49 | thread2.start(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lackofthreadsafetyinsingletons/SafeSingleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lackofthreadsafetyinsingletons; 2 | 3 | /** 4 | * 5 | * To ensure thread safety, we can synchronize the getInstance method. 6 | *

7 | * In this revised example, the getInstance method is synchronized, 8 | * ensuring that only one instance is created even when multiple threads access the method simultaneously. 9 | * 10 | */ 11 | public class SafeSingleton { 12 | private static SafeSingleton instance; 13 | 14 | /** 15 | * Private constructor to prevent instantiation. 16 | */ 17 | private SafeSingleton() { 18 | } 19 | 20 | /** 21 | * Returns the singleton instance. This method is synchronized to ensure 22 | * that only one instance is created in a multithreaded environment. 23 | * 24 | * @return the singleton instance. 25 | */ 26 | public static synchronized SafeSingleton getInstance() { 27 | if (instance == null) { 28 | instance = new SafeSingleton(); 29 | } 30 | return instance; 31 | } 32 | 33 | public void showMessage() { 34 | System.out.println("SafeSingleton instance method called."); 35 | } 36 | 37 | public static void main(String[] args) { 38 | Runnable task = () -> { 39 | SafeSingleton singleton = SafeSingleton.getInstance(); 40 | singleton.showMessage(); 41 | }; 42 | 43 | Thread thread1 = new Thread(task); 44 | Thread thread2 = new Thread(task); 45 | 46 | thread1.start(); 47 | thread2.start(); 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lackofthreadsafetyinsingletons/UnsafeSingleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lackofthreadsafetyinsingletons; 2 | 3 | /** 4 | * 5 | * A common issue with singletons is the lack of proper synchronization, 6 | * which can lead to multiple instances being created in a multithreaded environment. 7 | *

8 | * In this example, the getInstance method is not synchronized, 9 | * which can lead to multiple instances being created if multiple threads access the method simultaneously. 10 | * 11 | */ 12 | public class UnsafeSingleton { 13 | private static UnsafeSingleton instance; 14 | 15 | /** 16 | * Private constructor to prevent instantiation. 17 | */ 18 | private UnsafeSingleton() { 19 | } 20 | 21 | /** 22 | * Returns the singleton instance. This method is not synchronized, 23 | * leading to potential creation of multiple instances in a multithreaded environment. 24 | * 25 | * @return the singleton instance. 26 | */ 27 | public static UnsafeSingleton getInstance() { 28 | if (instance == null) { 29 | instance = new UnsafeSingleton(); 30 | } 31 | return instance; 32 | } 33 | 34 | public void showMessage() { 35 | System.out.println("UnsafeSingleton instance method called."); 36 | } 37 | 38 | public static void main(String[] args) { 39 | Runnable task = () -> { 40 | UnsafeSingleton singleton = UnsafeSingleton.getInstance(); 41 | singleton.showMessage(); 42 | }; 43 | 44 | Thread thread1 = new Thread(task); 45 | Thread thread2 = new Thread(task); 46 | 47 | thread1.start(); 48 | thread2.start(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lockcontention/LockContentionExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lockcontention; 2 | 3 | /** 4 | * 5 | * Lock contention occurs when multiple threads compete for the same lock, causing some threads to wait while another thread holds the lock. 6 | * This can lead to reduced performance due to increased waiting times and underutilized CPU resources. 7 | * 8 | * 9 | * In this example, both increment and getCounter methods synchronize on the same lock. 10 | * When multiple threads try to access these methods simultaneously, they experience high contention, reducing performance. 11 | * 12 | */ 13 | public class LockContentionExample { 14 | private final Object lock = new Object(); 15 | private int counter = 0; 16 | 17 | /** 18 | * Increments the counter. This method synchronizes on the same lock, 19 | * leading to high contention when accessed by multiple threads. 20 | */ 21 | public void increment() { 22 | synchronized (lock) { 23 | counter++; 24 | } 25 | } 26 | 27 | /** 28 | * Returns the counter value. 29 | * This method also synchronizes on the same lock, contributing to contention. 30 | * 31 | * @return the counter value. 32 | */ 33 | public int getCounter() { 34 | synchronized (lock) { 35 | return counter; 36 | } 37 | } 38 | 39 | public static void main(String[] args) { 40 | LockContentionExample lockContentionExample = new LockContentionExample(); 41 | 42 | Runnable task = () -> { 43 | for (int i = 0; i < 1000; i++) { 44 | lockContentionExample.increment(); 45 | } 46 | }; 47 | 48 | Thread thread1 = new Thread(task); 49 | Thread thread2 = new Thread(task); 50 | 51 | thread1.start(); 52 | thread2.start(); 53 | 54 | try { 55 | thread1.join(); 56 | thread2.join(); 57 | } catch (InterruptedException e) { 58 | e.printStackTrace(); 59 | } 60 | 61 | System.out.println("Final counter value: " + lockContentionExample.getCounter()); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lockcontention/LockContentionResolution.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lockcontention; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | /** 6 | * 7 | * To resolve lock contention, we can reduce the granularity of the locks, minimizing the critical sections that need synchronization. 8 | * 9 | * In this revised example, we use AtomicInteger to manage the counter. 10 | * AtomicInteger provides thread-safe operations without the need for explicit synchronization, significantly reducing lock contention. 11 | * 12 | */ 13 | public class LockContentionResolution { 14 | private final AtomicInteger counter = new AtomicInteger(); 15 | 16 | /** 17 | * Increments the counter using an atomic operation, reducing the need for explicit locks. 18 | */ 19 | public void increment() { 20 | counter.incrementAndGet(); 21 | } 22 | 23 | /** 24 | * Returns the counter value. This method is thread-safe without explicit locks. 25 | * 26 | * @return the counter value. 27 | */ 28 | public int getCounter() { 29 | return counter.get(); 30 | } 31 | 32 | public static void main(String[] args) { 33 | LockContentionResolution lockContentionResolution = new LockContentionResolution(); 34 | 35 | Runnable task = () -> { 36 | for (int i = 0; i < 1000; i++) { 37 | lockContentionResolution.increment(); 38 | } 39 | }; 40 | 41 | Thread thread1 = new Thread(task); 42 | Thread thread2 = new Thread(task); 43 | 44 | thread1.start(); 45 | thread2.start(); 46 | 47 | try { 48 | thread1.join(); 49 | thread2.join(); 50 | } catch (InterruptedException e) { 51 | e.printStackTrace(); 52 | } 53 | 54 | System.out.println("Final counter value: " + lockContentionResolution.getCounter()); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/lockcontention/StampedLockExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.lockcontention; 2 | 3 | import java.util.concurrent.locks.StampedLock; 4 | 5 | /** 6 | * 7 | * Another approach is to use StampedLock, which allows for more flexible lock handling, including optimistic reads. 8 | * 9 | * In this version, StampedLock is used to manage the counter. 10 | * StampedLock allows for optimistic reads, which can improve performance by avoiding locks if the data hasn't changed. 11 | * 12 | */ 13 | public class StampedLockExample { 14 | private final StampedLock lock = new StampedLock(); 15 | private int counter = 0; 16 | 17 | /** 18 | * Increments the counter using a write lock. 19 | */ 20 | public void increment() { 21 | long stamp = lock.writeLock(); 22 | try { 23 | counter++; 24 | } finally { 25 | lock.unlockWrite(stamp); 26 | } 27 | } 28 | 29 | /** 30 | * Returns the counter value using an optimistic read lock. 31 | * 32 | * @return the counter value. 33 | */ 34 | public int getCounter() { 35 | long stamp = lock.tryOptimisticRead(); 36 | int currentCounter = counter; 37 | if (!lock.validate(stamp)) { 38 | stamp = lock.readLock(); 39 | try { 40 | currentCounter = counter; 41 | } finally { 42 | lock.unlockRead(stamp); 43 | } 44 | } 45 | return currentCounter; 46 | } 47 | 48 | public static void main(String[] args) { 49 | StampedLockExample stampedLockExample = new StampedLockExample(); 50 | 51 | Runnable task = () -> { 52 | for (int i = 0; i < 1000; i++) { 53 | stampedLockExample.increment(); 54 | } 55 | }; 56 | 57 | Thread thread1 = new Thread(task); 58 | Thread thread2 = new Thread(task); 59 | 60 | thread1.start(); 61 | thread2.start(); 62 | 63 | try { 64 | thread1.join(); 65 | thread2.join(); 66 | } catch (InterruptedException e) { 67 | e.printStackTrace(); 68 | } 69 | 70 | System.out.println("Final counter value: " + stampedLockExample.getCounter()); 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/nonatomiccompoundactions/AtomicCompoundActionsExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.nonatomiccompoundactions; 2 | 3 | /** 4 | * 5 | * To resolve this issue, we can synchronize the method to ensure that the compound action is atomic. 6 | * 7 | * In this revised example, the incrementIfLessThan method is synchronized, 8 | * ensuring that the compound action is performed atomically. 9 | * This prevents race conditions and ensures correct results. 10 | * 11 | */ 12 | public class AtomicCompoundActionsExample { 13 | private int counter = 0; 14 | 15 | /** 16 | * Increments the counter if it is less than a specified limit. 17 | * This method is synchronized to ensure atomicity. 18 | * 19 | * @param limit the limit to check against. 20 | */ 21 | public synchronized void incrementIfLessThan(int limit) { 22 | if (counter < limit) { // Check 23 | counter++; // Then act 24 | } 25 | } 26 | 27 | /** 28 | * Returns the counter value. 29 | * 30 | * @return the counter value. 31 | */ 32 | public synchronized int getCounter() { 33 | return counter; 34 | } 35 | 36 | public static void main(String[] args) { 37 | AtomicCompoundActionsExample example = new AtomicCompoundActionsExample(); 38 | 39 | Runnable task = () -> { 40 | for (int i = 0; i < 1000; i++) { 41 | example.incrementIfLessThan(10); 42 | } 43 | }; 44 | 45 | Thread thread1 = new Thread(task); 46 | Thread thread2 = new Thread(task); 47 | 48 | thread1.start(); 49 | thread2.start(); 50 | 51 | try { 52 | thread1.join(); 53 | thread2.join(); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | System.out.println("Final counter value: " + example.getCounter()); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/nonatomiccompoundactions/AtomicIntegerExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.nonatomiccompoundactions; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | /** 6 | * 7 | * Another approach is to use the atomic classes provided by the java.util.concurrent package, 8 | * such as AtomicInteger, which provides atomic operations for integers. 9 | *

10 | *

11 | * In this version, the incrementIfLessThan method uses AtomicInteger and its compareAndSet method to ensure 12 | * that the compound action is performed atomically. 13 | *

14 | * This approach leverages the atomic classes in the java.util.concurrent package to provide thread safety without explicit synchronization. 15 | * 16 | */ 17 | public class AtomicIntegerExample { 18 | private final AtomicInteger counter = new AtomicInteger(); 19 | 20 | /** 21 | * Increments the counter if it is less than a specified limit. 22 | * This method uses atomic operations to ensure thread safety. 23 | * 24 | * @param limit the limit to check against. 25 | */ 26 | public void incrementIfLessThan(int limit) { 27 | while (true) { 28 | int current = counter.get(); 29 | if (current >= limit) { 30 | break; 31 | } 32 | if (counter.compareAndSet(current, current + 1)) { 33 | break; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * Returns the counter value. 40 | * 41 | * @return the counter value. 42 | */ 43 | public int getCounter() { 44 | return counter.get(); 45 | } 46 | 47 | public static void main(String[] args) { 48 | AtomicIntegerExample example = new AtomicIntegerExample(); 49 | 50 | Runnable task = () -> { 51 | for (int i = 0; i < 1000; i++) { 52 | example.incrementIfLessThan(10); 53 | } 54 | }; 55 | 56 | Thread thread1 = new Thread(task); 57 | Thread thread2 = new Thread(task); 58 | 59 | thread1.start(); 60 | thread2.start(); 61 | 62 | try { 63 | thread1.join(); 64 | thread2.join(); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | System.out.println("Final counter value: " + example.getCounter()); 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/nonatomiccompoundactions/NonAtomicCompoundActionsExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.nonatomiccompoundactions; 2 | 3 | /** 4 | * 5 | * Non-atomic compound actions occur when compound actions (e.g., check-then-act, read-modify-write) are performed without proper synchronization, 6 | * leading to race conditions and incorrect results. Here's an example demonstrating this problem along with a resolution. 7 | *

8 | * In this example, the incrementIfLessThan method performs a non-atomic compound action. 9 | * If multiple threads execute this method concurrently, they may both pass the check before either increments the counter, 10 | * leading to incorrect results. 11 | * 12 | */ 13 | public class NonAtomicCompoundActionsExample { 14 | private int counter = 0; 15 | 16 | /** 17 | * Increments the counter if it is less than a specified limit. 18 | * This method is not synchronized, leading to potential race conditions. 19 | * 20 | * @param limit the limit to check against. 21 | */ 22 | public void incrementIfLessThan(int limit) { 23 | if (counter < limit) { // Check 24 | counter++; // Then act 25 | } 26 | } 27 | 28 | /** 29 | * Returns the counter value. 30 | * 31 | * @return the counter value. 32 | */ 33 | public int getCounter() { 34 | return counter; 35 | } 36 | 37 | public static void main(String[] args) { 38 | NonAtomicCompoundActionsExample example = new NonAtomicCompoundActionsExample(); 39 | 40 | Runnable task = () -> { 41 | for (int i = 0; i < 1000; i++) { 42 | example.incrementIfLessThan(10); 43 | } 44 | }; 45 | 46 | Thread thread1 = new Thread(task); 47 | Thread thread2 = new Thread(task); 48 | 49 | thread1.start(); 50 | thread2.start(); 51 | 52 | try { 53 | thread1.join(); 54 | thread2.join(); 55 | } catch (InterruptedException e) { 56 | e.printStackTrace(); 57 | } 58 | 59 | System.out.println("Final counter value: " + example.getCounter()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/racecondition/AccountAmount.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.racecondition; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | /** 8 | * A class representing an account amount with various methods for incrementing the amount value. 9 | */ 10 | public class AccountAmount { 11 | private int amount; // The current amount value 12 | private final AtomicInteger atomicInteger = new AtomicInteger(0); // Thread-safe atomic integer 13 | private final Lock lock = new ReentrantLock(); // Lock for synchronization 14 | 15 | /** 16 | * Retrieves the current amount value. 17 | * 18 | * @return The current amount value. 19 | */ 20 | public int getAmount() { 21 | return amount; 22 | } 23 | 24 | /** 25 | * Increments the amount value without any synchronization. 26 | */ 27 | public void unsafeIncrementAmount() { 28 | amount++; 29 | } 30 | 31 | /** 32 | * Increments the amount value with lock-based synchronization. 33 | */ 34 | public void safeLockIncrementAmount() { 35 | while (true) { 36 | if (lock.tryLock()) { 37 | try { 38 | amount++; 39 | break; 40 | } finally { 41 | lock.unlock(); 42 | } 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * Increments the amount value with synchronized block-based synchronization. 49 | */ 50 | public void safeSynchronizedIncrementAmount() { 51 | synchronized (AccountAmount.class) { 52 | amount++; 53 | } 54 | } 55 | 56 | /** 57 | * Increments the amount value using an atomic operation. 58 | */ 59 | public void incrementAtomicAmount() { 60 | atomicInteger.incrementAndGet(); 61 | } 62 | 63 | /** 64 | * Retrieves the atomic integer used for atomic operations. 65 | * 66 | * @return The atomic integer. 67 | */ 68 | public AtomicInteger getAtomicInteger() { 69 | return atomicInteger; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/startingthreadinconstructor/ThreadInConstructor.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.startingthreadinconstructor; 2 | 3 | /** 4 | * 5 | * Starting a thread within a constructor can lead to unpredictable behavior or issues where the thread starts before the object is fully constructed. 6 | * 7 | * In this example, the ThreadInConstructor class starts the thread within the constructor. 8 | * This can lead to issues where the thread starts before the object is fully initialized, potentially causing unexpected behavior. 9 | * 10 | */ 11 | public class ThreadInConstructor extends Thread { 12 | private final String message; 13 | 14 | /** 15 | * Constructor starts the thread immediately. 16 | * This is problematic as the object might not be fully constructed. 17 | * 18 | * @param message the message to be printed by the thread. 19 | */ 20 | public ThreadInConstructor(String message) { 21 | this.message = message; 22 | start(); // Starting thread in the constructor 23 | } 24 | 25 | /** 26 | * Run method prints the message. 27 | */ 28 | @Override 29 | public void run() { 30 | System.out.println(message); 31 | } 32 | 33 | public static void main(String[] args) { 34 | new ThreadInConstructor("Thread started in constructor"); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/startingthreadinconstructor/ThreadStartedOutsideConstructor.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.startingthreadinconstructor; 2 | 3 | /** 4 | * 5 | * To resolve this issue, start the thread outside the constructor, 6 | * ensuring that the object is fully constructed before the thread starts. 7 | * 8 | * In this revised example, the thread is created in the main method after the object is fully constructed, 9 | * ensuring that the thread starts at an appropriate time. 10 | * 11 | */ 12 | public class ThreadStartedOutsideConstructor extends Thread { 13 | private final String message; 14 | 15 | /** 16 | * Constructor initializes the message. 17 | * 18 | * @param message the message to be printed by the thread. 19 | */ 20 | public ThreadStartedOutsideConstructor(String message) { 21 | this.message = message; 22 | } 23 | 24 | /** 25 | * Run method prints the message. 26 | */ 27 | @Override 28 | public void run() { 29 | System.out.println(message); 30 | } 31 | 32 | public static void main(String[] args) { 33 | ThreadStartedOutsideConstructor thread = new ThreadStartedOutsideConstructor("Thread started outside constructor"); 34 | thread.start(); // Starting thread outside the constructor 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/startingthreadinconstructor/ThreadUsingFactory.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.startingthreadinconstructor; 2 | 3 | /** 4 | * 5 | * Another approach is to use factory methods to create and start the thread, 6 | * ensuring separation of concerns and better control over the thread lifecycle. 7 | * 8 | * In this version, the ThreadUsingFactory class provides a private constructor 9 | * and a factory method createAndStart to create and start the thread. 10 | * This ensures that the thread starts at an appropriate time and provides better encapsulation of the thread creation logic. 11 | * 12 | */ 13 | public class ThreadUsingFactory { 14 | private final String message; 15 | 16 | /** 17 | * Private constructor to enforce usage of factory method. 18 | * 19 | * @param message the message to be printed by the thread. 20 | */ 21 | private ThreadUsingFactory(String message) { 22 | this.message = message; 23 | } 24 | 25 | /** 26 | * Factory method to create and start the thread. 27 | * 28 | * @param message the message to be printed by the thread. 29 | * @return the created thread. 30 | */ 31 | public static ThreadUsingFactory createAndStart(String message) { 32 | ThreadUsingFactory thread = new ThreadUsingFactory(message); 33 | thread.start(); 34 | return thread; 35 | } 36 | 37 | /** 38 | * Run method prints the message. 39 | */ 40 | private void run() { 41 | System.out.println(message); 42 | } 43 | 44 | /** 45 | * Start method to begin thread execution. 46 | */ 47 | private void start() { 48 | new Thread(this::run).start(); 49 | } 50 | 51 | public static void main(String[] args) { 52 | ThreadUsingFactory.createAndStart("Thread started using factory method"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/threadleakage/ThreadLeakageExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.threadleakage; 2 | 3 | /** 4 | * Demonstrates thread leakage by continuously creating and starting new threads without proper termination. 5 | */ 6 | public class ThreadLeakageExample { 7 | 8 | public static void main(String[] args) { 9 | ThreadLeakageExample example = new ThreadLeakageExample(); 10 | example.startThreads(); 11 | } 12 | 13 | /** 14 | * Continuously starts new threads without properly managing their lifecycle, leading to thread leakage. 15 | */ 16 | public void startThreads() { 17 | while (true) { 18 | new Thread(() -> { 19 | // Simulate some work with a sleep 20 | try { 21 | Thread.sleep(1000); 22 | } catch (InterruptedException e) { 23 | Thread.currentThread().interrupt(); 24 | } 25 | }).start(); 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/threadleakage/ThreadLeakageResolution.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.threadleakage; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * Demonstrates the resolution of thread leakage by using a thread pool to manage threads. 8 | */ 9 | public class ThreadLeakageResolution { 10 | 11 | private final ExecutorService executorService; 12 | 13 | /** 14 | * Initializes the ThreadLeakageResolution with a fixed thread pool. 15 | */ 16 | public ThreadLeakageResolution() { 17 | // Initialize a fixed thread pool with a fixed number of threads 18 | this.executorService = Executors.newFixedThreadPool(10); 19 | } 20 | 21 | public static void main(String[] args) { 22 | ThreadLeakageResolution example = new ThreadLeakageResolution(); 23 | example.startThreads(); 24 | } 25 | 26 | /** 27 | * Submits tasks to the thread pool for execution, preventing thread leakage. 28 | * Submits a fixed number of tasks to the executor service for demonstration purposes. 29 | */ 30 | public void startThreads() { 31 | for (int i = 0; i < 100; i++) { // Submitting a fixed number of tasks for demonstration 32 | executorService.submit(() -> { 33 | // Simulate some work with a sleep 34 | try { 35 | Thread.sleep(1000); 36 | } catch (InterruptedException e) { 37 | Thread.currentThread().interrupt(); 38 | } 39 | }); 40 | } 41 | 42 | // Shutdown the executor service after tasks are completed 43 | executorService.shutdown(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/threadsinsteadoftasks/CompletableFutureExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.threadsinsteadoftasks; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.concurrent.ExecutionException; 5 | 6 | /** 7 | * Another approach is to use CompletableFuture, 8 | * which is part of the java.util.concurrent package and allows for more flexible task management and asynchronous programming. 9 | *

10 | *

11 | * In this version, CompletableFuture.runAsync is used to execute tasks asynchronously. 12 | * CompletableFuture provides a rich API for composing and managing asynchronous tasks, making it easier to handle complex workflows. 13 | */ 14 | public class CompletableFutureExample { 15 | /** 16 | * A simple task that prints the thread name. 17 | */ 18 | public void performTask() { 19 | CompletableFuture task1 = CompletableFuture.runAsync(() -> System.out.println("Task executed by: " + Thread.currentThread().getName())); 20 | CompletableFuture task2 = CompletableFuture.runAsync(() -> System.out.println("Task executed by: " + Thread.currentThread().getName())); 21 | 22 | // Wait for all tasks to complete 23 | try { 24 | CompletableFuture.allOf(task1, task2).get(); 25 | } catch (InterruptedException | ExecutionException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | 30 | public static void main(String[] args) { 31 | CompletableFutureExample manager = new CompletableFutureExample(); 32 | manager.performTask(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/threadsinsteadoftasks/DirectThreadManagement.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.threadsinsteadoftasks; 2 | 3 | /** 4 | * Directly creating and managing threads instead of using the Executor framework can lead to poor scalability and complex error handling. 5 | *

6 | * In this example, tasks are executed by directly creating and managing threads. 7 | * This approach can lead to problems such as unbounded thread creation, poor resource management, and difficulty in handling errors. 8 | */ 9 | public class DirectThreadManagement { 10 | /** 11 | * A simple task that prints the thread name. 12 | */ 13 | public void performTask() { 14 | Runnable task = () -> { 15 | System.out.println("Task executed by: " + Thread.currentThread().getName()); 16 | }; 17 | 18 | // Directly creating and starting threads 19 | Thread thread1 = new Thread(task); 20 | Thread thread2 = new Thread(task); 21 | 22 | thread1.start(); 23 | thread2.start(); 24 | 25 | try { 26 | thread1.join(); 27 | thread2.join(); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | DirectThreadManagement manager = new DirectThreadManagement(); 35 | manager.performTask(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/threadsinsteadoftasks/ExecutorFrameworkExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.threadsinsteadoftasks; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | 8 | /** 9 | * To resolve these issues, we can use the Executor framework, which provides a higher-level API for managing threads. 10 | *

11 | *

12 | * In this revised example, tasks are submitted to an ExecutorService with a fixed thread pool. 13 | * The Executor framework handles thread creation, management, 14 | * and resource cleanup, providing better scalability and error handling. 15 | */ 16 | public class ExecutorFrameworkExample { 17 | /** 18 | * A simple task that prints the thread name. 19 | */ 20 | public void performTask() { 21 | Runnable task = () -> { 22 | System.out.println("Task executed by: " + Thread.currentThread().getName()); 23 | }; 24 | 25 | // Using ExecutorService to manage threads 26 | ExecutorService executor = Executors.newFixedThreadPool(2); 27 | 28 | executor.submit(task); 29 | executor.submit(task); 30 | 31 | // Shutdown the executor and wait for tasks to finish 32 | executor.shutdown(); 33 | try { 34 | executor.awaitTermination(1, TimeUnit.MINUTES); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | public static void main(String[] args) { 41 | ExecutorFrameworkExample manager = new ExecutorFrameworkExample(); 42 | manager.performTask(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/usingthreadsafecollectionsincorrectly/BaseListUsage.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.usingthreadsafecollectionsincorrectly; 2 | 3 | import java.util.Collection; 4 | 5 | public interface BaseListUsage { 6 | void addIfAbsent(String element); 7 | 8 | int size(); 9 | 10 | Collection getCollection(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/usingthreadsafecollectionsincorrectly/CorrectUsage.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.usingthreadsafecollectionsincorrectly; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CopyOnWriteArrayList; 5 | 6 | /** 7 | * 8 | * To resolve this issue, we need to ensure that the check and add operation are performed atomically. 9 | * One way to do this is to synchronize the method or the critical section. 10 | * 11 | * By synchronizing the addIfAbsent method, we ensure that only one thread can execute it at a time, making the operation atomic. 12 | * 13 | */ 14 | public class CorrectUsage implements BaseListUsage { 15 | private final List list = new CopyOnWriteArrayList<>(); 16 | 17 | /** 18 | * Adds a new element to the list if it's not already present. 19 | * This method is synchronized to ensure thread-safety. 20 | * 21 | * @param element the element to add to the list. 22 | */ 23 | public synchronized void addIfAbsent(String element) { 24 | if (!list.contains(element)) { 25 | list.add(element); 26 | } 27 | } 28 | 29 | /** 30 | * Returns the size of the list. 31 | * 32 | * @return the number of elements in the list. 33 | */ 34 | public int size() { 35 | return list.size(); 36 | } 37 | 38 | @Override 39 | public List getCollection() { 40 | return list; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/usingthreadsafecollectionsincorrectly/IncorrectUsage.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.usingthreadsafecollectionsincorrectly; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CopyOnWriteArrayList; 5 | 6 | /** 7 | * Thread-safe collections in Java, such as those from the java.util.concurrent package, 8 | * are designed to handle concurrent access. 9 | * However, improper use of these collections can still lead to concurrency issues. 10 | *

11 | *

12 | * In this example, even though CopyOnWriteArrayList is thread-safe, 13 | * the addIfAbsent method is not thread-safe because the contains check and the add operation are not atomic. 14 | * This can lead to a race condition where multiple threads might add the same element simultaneously. 15 | */ 16 | public class IncorrectUsage implements BaseListUsage { 17 | private final List list = new CopyOnWriteArrayList<>(); 18 | 19 | /** 20 | * Adds a new element to the list if it's not already present. 21 | * This method is not thread-safe despite using a thread-safe collection. 22 | * 23 | * @param element the element to add to the list. 24 | */ 25 | public void addIfAbsent(String element) { 26 | if (!list.contains(element)) { 27 | list.add(element); 28 | } 29 | } 30 | 31 | /** 32 | * Returns the size of the list. 33 | * 34 | * @return the number of elements in the list. 35 | */ 36 | public int size() { 37 | return list.size(); 38 | } 39 | 40 | @Override 41 | public List getCollection() { 42 | return list; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/usingthreadsafecollectionsincorrectly/OptimizedUsage.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.usingthreadsafecollectionsincorrectly; 2 | 3 | import java.util.Collection; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * Another approach is to use a ConcurrentHashMap to achieve atomic check-and-add operations. 8 | * The ConcurrentHashMap provides thread-safe methods, simplifying the code. 9 | * 10 | * In this case, ConcurrentHashMap.newKeySet() creates a thread-safe set backed by a ConcurrentHashMap. 11 | * The add method of this set is atomic, ensuring that the element is added only if it is not already present. 12 | */ 13 | public class OptimizedUsage implements BaseListUsage { 14 | private final Collection set = ConcurrentHashMap.newKeySet(); 15 | 16 | /** 17 | * Adds a new element to the set if it's not already present. 18 | * This method uses ConcurrentHashMap to ensure thread-safety. 19 | * 20 | * @param element the element to add to the set. 21 | */ 22 | public void addIfAbsent(String element) { 23 | set.add(element); 24 | } 25 | 26 | /** 27 | * Returns the size of the set. 28 | * 29 | * @return the number of elements in the set. 30 | */ 31 | public int size() { 32 | return set.size(); 33 | } 34 | 35 | @Override 36 | public Collection getCollection() { 37 | return set; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/antipatterns/usingthreadsafecollectionsincorrectly/UsageExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.antipatterns.usingthreadsafecollectionsincorrectly; 2 | 3 | public class UsageExample { 4 | public static void runExample(BaseListUsage usage) { 5 | 6 | // Create threads to perform operations on the list 7 | Thread thread1 = new Thread(() -> { 8 | for (int i = 0; i < 100; i++) { 9 | usage.addIfAbsent("Element " + i); 10 | } 11 | }); 12 | 13 | Thread thread2 = new Thread(() -> { 14 | for (int i = 50; i < 150; i++) { 15 | usage.addIfAbsent("Element " + i); 16 | } 17 | }); 18 | 19 | // Start the threads 20 | thread1.start(); 21 | thread2.start(); 22 | 23 | // Wait for both threads to complete 24 | try { 25 | thread1.join(); 26 | thread2.join(); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | // Print the final size of the list 32 | System.out.println("Final size of the list: " + usage.size()); 33 | 34 | // Print elements in the list to demonstrate correct usage 35 | System.out.println("Elements in the list:"); 36 | for (T element : usage.getCollection()) { 37 | System.out.println(element); 38 | } 39 | } 40 | 41 | public static void main(String[] args) { 42 | CorrectUsage correctUsage = new CorrectUsage(); 43 | IncorrectUsage incorrectUsage = new IncorrectUsage(); 44 | OptimizedUsage optimizedUsage = new OptimizedUsage(); 45 | runExample(correctUsage); 46 | runExample(incorrectUsage); 47 | runExample(optimizedUsage); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/activeobject/ActiveObject.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.activeobject; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * The ActiveObject class decouples method execution from method invocation to enhance concurrency. 9 | * It encapsulates method calls as objects, allowing them to be executed asynchronously in a separate 10 | * thread without blocking the calling thread. This pattern is useful for improving responsiveness 11 | * and resource utilization in concurrent applications. 12 | */ 13 | public class ActiveObject { 14 | private final ExecutorService executor = Executors.newSingleThreadExecutor(); 15 | 16 | /** 17 | * Asynchronously invokes the sayHello method with the given name. 18 | * 19 | * @param name The name to include in the greeting message. 20 | * @return A Future representing the result of the computation. 21 | */ 22 | public Future sayHello(String name) { 23 | return executor.submit(() -> { 24 | Thread.sleep(100); // Simulate delay 25 | return "Hello, " + name; 26 | }); 27 | } 28 | 29 | /** 30 | * Shuts down the executor service associated with this active object, releasing any resources. 31 | */ 32 | public void shutdown() { 33 | executor.shutdown(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/atomics/AtomicIntegerFieldUpdaterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.atomics; 2 | 3 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 4 | 5 | /** 6 | * Demonstrates the usage of AtomicIntegerFieldUpdater in a multithreaded environment. 7 | *

8 | * AtomicIntegerFieldUpdater provides atomic operations on integer fields of objects. 9 | */ 10 | public class AtomicIntegerFieldUpdaterExample { 11 | 12 | // Define a class with an integer field 13 | static class MyClass { 14 | volatile int value; 15 | } 16 | 17 | /** 18 | * MyClass is a simple class with a volatile integer field named value. 19 | * An AtomicIntegerFieldUpdater named updater is created for the value field of MyClass. 20 | * Two threads are created: an updater thread and a reader thread. 21 | * The updater thread updates the value field of myObject using updater.set() method. 22 | * The reader thread reads the value field of myObject using updater.get() method. 23 | * Both threads run concurrently. 24 | * After both threads have completed, the main thread prints the final state of the field. 25 | */ 26 | public static void main(String[] args) { 27 | // Create an AtomicIntegerFieldUpdater for the 'value' field of MyClass 28 | AtomicIntegerFieldUpdater updater = AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "value"); 29 | 30 | // Create an instance of MyClass 31 | MyClass myObject = new MyClass(); 32 | 33 | // Define worker threads 34 | Thread updaterThread = new Thread(() -> { 35 | // Update the value using AtomicIntegerFieldUpdater 36 | updater.set(myObject, 10); 37 | System.out.println("Updater Thread updated value to: " + updater.get(myObject)); 38 | }); 39 | 40 | Thread readerThread = new Thread(() -> { 41 | // Read the value 42 | int value = updater.get(myObject); 43 | System.out.println("Reader Thread read value: " + value); 44 | }); 45 | 46 | // Start worker threads 47 | updaterThread.start(); 48 | readerThread.start(); 49 | 50 | // Wait for worker threads to complete 51 | try { 52 | updaterThread.join(); 53 | readerThread.join(); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/atomics/AtomicLongFieldUpdaterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.atomics; 2 | 3 | import java.util.concurrent.atomic.AtomicLongFieldUpdater; 4 | 5 | /** 6 | * Demonstrates the usage of AtomicLongFieldUpdater in a multithreaded environment. 7 | *

8 | * AtomicLongFieldUpdater provides atomic operations on long fields of objects. 9 | */ 10 | public class AtomicLongFieldUpdaterExample { 11 | 12 | // Define a class with a long field 13 | static class MyClass { 14 | volatile long value; 15 | } 16 | 17 | /** 18 | * MyClass is a simple class with a volatile long field named value. 19 | * An AtomicLongFieldUpdater named updater is created for the value field of MyClass. 20 | * Two threads are created: an updater thread and a reader thread. 21 | * The updater thread updates the value field of myObject using updater.set() method. 22 | * The reader thread reads the value field of myObject using updater.get() method. 23 | * Both threads run concurrently. 24 | * After both threads have completed, the main thread prints the final state of the field. 25 | */ 26 | public static void main(String[] args) { 27 | // Create an AtomicLongFieldUpdater for the 'value' field of MyClass 28 | AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(MyClass.class, "value"); 29 | 30 | // Create an instance of MyClass 31 | MyClass myObject = new MyClass(); 32 | 33 | // Define worker threads 34 | Thread updaterThread = new Thread(() -> { 35 | // Update the value using AtomicLongFieldUpdater 36 | updater.set(myObject, 10); 37 | System.out.println("Updater Thread updated value to: " + updater.get(myObject)); 38 | }); 39 | 40 | Thread readerThread = new Thread(() -> { 41 | // Read the value 42 | long value = updater.get(myObject); 43 | System.out.println("Reader Thread read value: " + value); 44 | }); 45 | 46 | // Start worker threads 47 | updaterThread.start(); 48 | readerThread.start(); 49 | 50 | // Wait for worker threads to complete 51 | try { 52 | updaterThread.join(); 53 | readerThread.join(); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/atomics/AtomicReferenceArrayExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.atomics; 2 | 3 | import java.util.concurrent.atomic.AtomicReferenceArray; 4 | 5 | /** 6 | * Demonstrates the usage of AtomicReferenceArray in a multithreaded environment. 7 | * AtomicReferenceArray provides atomic operations on arrays of reference values. 8 | */ 9 | public class AtomicReferenceArrayExample { 10 | /** 11 | * An AtomicReferenceArray named array is created with an initial size of 3 and populated with initial values. 12 | * The updater thread updates the value at index 1 of the array using the compareAndSet method, which atomically compares the current value with an expected value and sets the new value if the comparison is successful. 13 | * The reader thread simply reads the value at index 1 of the array. 14 | * Both threads run concurrently. 15 | * After both threads have completed, the main thread prints the final state of the array. 16 | */ 17 | public static void main(String[] args) { 18 | // Create an AtomicReferenceArray with initial values 19 | AtomicReferenceArray array = new AtomicReferenceArray<>(3); 20 | array.set(0, "Value 1"); 21 | array.set(1, "Value 2"); 22 | array.set(2, "Value 3"); 23 | 24 | // Define worker threads 25 | Thread updaterThread = new Thread(() -> { 26 | // Update the value at index 1 27 | array.compareAndSet(1, "Value 2", "New Value 2"); 28 | System.out.println("Updater Thread updated value at index 1 to: " + array.get(1)); 29 | }); 30 | 31 | Thread readerThread = new Thread(() -> { 32 | // Read the value at index 1 33 | String value = array.get(1); 34 | System.out.println("Reader Thread read value at index 1: " + value); 35 | }); 36 | 37 | // Start worker threads 38 | updaterThread.start(); 39 | readerThread.start(); 40 | 41 | // Wait for worker threads to complete 42 | try { 43 | updaterThread.join(); 44 | readerThread.join(); 45 | } catch (InterruptedException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/atomics/AtomicReferenceFieldUpdaterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.atomics; 2 | 3 | import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; 4 | 5 | /** 6 | * Demonstrates the usage of AtomicReferenceFieldUpdater in a multithreaded environment. 7 | *

8 | * AtomicReferenceFieldUpdater provides atomic operations on reference fields of objects. 9 | */ 10 | public class AtomicReferenceFieldUpdaterExample { 11 | 12 | // Define a class with a reference field 13 | static class MyClass { 14 | volatile String value; 15 | } 16 | 17 | /** 18 | * MyClass is a simple class with a volatile reference field named value. 19 | * An AtomicReferenceFieldUpdater named updater is created for the value field of MyClass. 20 | * Two threads are created: an updater thread and a reader thread. 21 | * The updater thread updates the value field of myObject using updater.set() method. 22 | * The reader thread reads the value field of myObject using updater.get() method. 23 | * Both threads run concurrently. 24 | * After both threads have completed, the main thread prints the final state of the field. 25 | */ 26 | public static void main(String[] args) { 27 | // Create an AtomicReferenceFieldUpdater for the 'value' field of MyClass 28 | AtomicReferenceFieldUpdater updater = 29 | AtomicReferenceFieldUpdater.newUpdater(MyClass.class, String.class, "value"); 30 | 31 | // Create an instance of MyClass 32 | MyClass myObject = new MyClass(); 33 | 34 | // Define worker threads 35 | Thread updaterThread = new Thread(() -> { 36 | // Update the value using AtomicReferenceFieldUpdater 37 | updater.set(myObject, "New Value"); 38 | System.out.println("Updater Thread updated value to: " + updater.get(myObject)); 39 | }); 40 | 41 | Thread readerThread = new Thread(() -> { 42 | // Read the value 43 | String value = updater.get(myObject); 44 | System.out.println("Reader Thread read value: " + value); 45 | }); 46 | 47 | // Start worker threads 48 | updaterThread.start(); 49 | readerThread.start(); 50 | 51 | // Wait for worker threads to complete 52 | try { 53 | updaterThread.join(); 54 | readerThread.join(); 55 | } catch (InterruptedException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/balking/BalkingPatternExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.balking; 2 | 3 | /** 4 | * The BalkingPatternExample class demonstrates the Balking design pattern, which prevents an action from 5 | * being executed if it is not in the appropriate state. It provides methods for changing and saving state, 6 | * ensuring that the save operation is only performed when the state is dirty. 7 | */ 8 | public class BalkingPatternExample { 9 | private boolean isDirty = false; 10 | 11 | /** 12 | * Marks the state as dirty, indicating that it needs to be saved. 13 | */ 14 | public synchronized void change() { 15 | isDirty = true; 16 | } 17 | 18 | /** 19 | * Saves the state if it is dirty, preventing unnecessary saving operations. 20 | */ 21 | public synchronized void save() { 22 | if (!isDirty) { 23 | return; // Balking: If not dirty, do nothing 24 | } 25 | // perform saving 26 | isDirty = false; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/collections/BlockingQueueSimpleExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | 6 | /** 7 | * This class demonstrates the usage of a blocking queue in a producer-consumer scenario. 8 | * A blocking queue with a capacity of 5 is created using ArrayBlockingQueue. 9 | * A producer thread is created, which continuously adds elements to the blocking queue. 10 | * The producer puts elements into the queue using the put() method. If the queue is full, 11 | * the put() method blocks until space becomes available. 12 | * A consumer thread is created, which continuously removes elements from the blocking queue. 13 | * The consumer takes elements from the queue using the take() method. If the queue is empty, 14 | * the take() method blocks until elements become available. 15 | * Both producer and consumer threads run in parallel, simulating the production and consumption 16 | * of elements from the blocking queue. Elements produced are printed with "Produced" prefix, 17 | * and elements consumed are printed with "Consumed" prefix, along with their respective values. 18 | */ 19 | public class BlockingQueueSimpleExample { 20 | public static void main(String[] args) { 21 | // Create a blocking queue with a capacity of 5 22 | BlockingQueue blockingQueue = new ArrayBlockingQueue<>(5); 23 | 24 | // Producer thread 25 | Thread producer = new Thread(() -> { 26 | try { 27 | for (int i = 0; i < 10; i++) { 28 | // Put elements into the queue 29 | blockingQueue.put(i); 30 | System.out.println("Produced: " + i); 31 | Thread.sleep(1000); 32 | } 33 | } catch (InterruptedException e) { 34 | Thread.currentThread().interrupt(); 35 | } 36 | }); 37 | 38 | // Consumer thread 39 | Thread consumer = new Thread(() -> { 40 | try { 41 | for (int i = 0; i < 10; i++) { 42 | // Take elements from the queue 43 | int value = blockingQueue.take(); 44 | System.out.println("Consumed: " + value); 45 | Thread.sleep(2000); 46 | } 47 | } catch (InterruptedException e) { 48 | Thread.currentThread().interrupt(); 49 | } 50 | }); 51 | 52 | // Start the producer and consumer threads 53 | producer.start(); 54 | consumer.start(); 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/collections/ConcurrentHashMapExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | /** 6 | * The ConcurrentHashMapExample class demonstrates the usage of the ConcurrentHashMap, which is a thread-safe variant of HashMap. 7 | * It provides methods to put, get, and check for the presence of a key in the concurrent hash map. 8 | */ 9 | public class ConcurrentHashMapExample { 10 | private final ConcurrentHashMap map = new ConcurrentHashMap<>(); 11 | 12 | /** 13 | * Puts a key-value pair into the concurrent hash map. 14 | * 15 | * @param key The key to be inserted into the map. 16 | * @param value The value corresponding to the key to be inserted into the map. 17 | */ 18 | public void put(String key, Integer value) { 19 | map.put(key, value); 20 | } 21 | 22 | /** 23 | * Retrieves the value associated with the specified key from the concurrent hash map. 24 | * 25 | * @param key The key whose associated value is to be retrieved. 26 | * @return The value to which the specified key is mapped, or null if the key is not present in the map. 27 | */ 28 | public Integer get(String key) { 29 | return map.get(key); 30 | } 31 | 32 | /** 33 | * Checks whether the concurrent hash map contains the specified key. 34 | * 35 | * @param key The key whose presence in the map is to be tested. 36 | * @return true if the map contains a mapping for the specified key, otherwise false. 37 | */ 38 | public boolean containsKey(String key) { 39 | return map.containsKey(key); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/collections/ConcurrentSkipListMapExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import java.util.concurrent.ConcurrentSkipListMap; 4 | 5 | /** 6 | * Demonstrates the usage of ConcurrentSkipListMap in a multithreaded environment. 7 | * Where multiple threads can safely modify the map without explicit synchronization. 8 | */ 9 | public class ConcurrentSkipListMapExample { 10 | 11 | /** 12 | * We create a ConcurrentSkipListMap named skipListMap. 13 | * We put some initial key-value pairs into the map. 14 | * We print the initial state of the map. 15 | * We create two threads (thread1 and thread2) to concurrently modify the map by adding new key-value pairs. 16 | * Each thread adds a new key-value pair to the map. 17 | * We start both threads and wait for them to finish using the join() method. 18 | * Finally, we print the final state of the map after the threads have finished executing. 19 | */ 20 | public static void main(String[] args) { 21 | // Create a ConcurrentSkipListMap 22 | ConcurrentSkipListMap skipListMap = new ConcurrentSkipListMap<>(); 23 | 24 | // Put elements into the map 25 | skipListMap.put(3, "Apple"); 26 | skipListMap.put(1, "Banana"); 27 | skipListMap.put(5, "Orange"); 28 | 29 | // Print the initial map 30 | System.out.println("Initial Map: " + skipListMap); 31 | 32 | // Create and start threads to modify the map concurrently 33 | Thread thread1 = new Thread(() -> { 34 | skipListMap.put(2, "Mango"); 35 | System.out.println("Thread 1 added (2, Mango)"); 36 | }); 37 | 38 | Thread thread2 = new Thread(() -> { 39 | skipListMap.put(4, "Pineapple"); 40 | System.out.println("Thread 2 added (4, Pineapple)"); 41 | }); 42 | 43 | thread1.start(); 44 | thread2.start(); 45 | 46 | try { 47 | // Wait for threads to finish 48 | thread1.join(); 49 | thread2.join(); 50 | } catch (InterruptedException e) { 51 | e.printStackTrace(); 52 | } 53 | 54 | // Print the final map 55 | System.out.println("Final Map: " + skipListMap); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/collections/ConcurrentSkipListSetExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import java.util.concurrent.ConcurrentSkipListSet; 4 | 5 | /** 6 | * The ConcurrentSkipListSetExample class demonstrates the usage of ConcurrentSkipListSet, which is a thread-safe variant of TreeSet. 7 | * It provides methods to add, check for the presence of, and remove elements from the set. 8 | */ 9 | public class ConcurrentSkipListSetExample { 10 | private final ConcurrentSkipListSet set = new ConcurrentSkipListSet<>(); 11 | 12 | /** 13 | * Adds the specified element to the set. 14 | * 15 | * @param value The element to be added to the set. 16 | */ 17 | public void add(int value) { 18 | set.add(value); 19 | } 20 | 21 | /** 22 | * Checks whether the set contains the specified element. 23 | * 24 | * @param value The element whose presence in the set is to be tested. 25 | * @return true if the set contains the specified element, otherwise false. 26 | */ 27 | public boolean contains(int value) { 28 | return set.contains(value); 29 | } 30 | 31 | /** 32 | * Removes the specified element from the set if it is present. 33 | * 34 | * @param value The element to be removed from the set, if present. 35 | */ 36 | public void remove(int value) { 37 | set.remove(value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/collections/CopyOnWriteArrayListExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import java.util.concurrent.CopyOnWriteArrayList; 4 | 5 | /** 6 | * The CopyOnWriteArrayListExample class demonstrates the usage of CopyOnWriteArrayList, which is a thread-safe variant of ArrayList. 7 | * It provides methods to add, check for the presence of, and remove elements from the list. 8 | */ 9 | public class CopyOnWriteArrayListExample { 10 | private final CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); 11 | 12 | /** 13 | * Adds the specified element to the list. 14 | * 15 | * @param element The element to be added to the list. 16 | */ 17 | public void add(String element) { 18 | list.add(element); 19 | } 20 | 21 | /** 22 | * Checks whether the list contains the specified element. 23 | * 24 | * @param element The element whose presence in the list is to be tested. 25 | * @return true if the list contains the specified element, otherwise false. 26 | */ 27 | public boolean contains(String element) { 28 | return list.contains(element); 29 | } 30 | 31 | /** 32 | * Removes the specified element from the list if it is present. 33 | * 34 | * @param element The element to be removed from the list, if present. 35 | */ 36 | public void remove(String element) { 37 | list.remove(element); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/doublechecklocking/DoubleCheckedLockingSingleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.doublechecklocking; 2 | 3 | /** 4 | * The DoubleCheckedLockingSingleton class implements the Singleton pattern using double-checked locking. 5 | * It ensures that only one instance of the class is created and provides a global point of access to it. 6 | */ 7 | public class DoubleCheckedLockingSingleton { 8 | private volatile static DoubleCheckedLockingSingleton instance; 9 | 10 | /** 11 | * Private constructor to prevent instantiation from outside the class. 12 | */ 13 | private DoubleCheckedLockingSingleton() { 14 | // Private constructor to prevent instantiation. 15 | } 16 | 17 | /** 18 | * Returns the instance of the DoubleCheckedLockingSingleton class. 19 | * 20 | * @return The Singleton instance. 21 | */ 22 | public static DoubleCheckedLockingSingleton getInstance() { 23 | if (instance == null) { 24 | synchronized (DoubleCheckedLockingSingleton.class) { 25 | if (instance == null) { 26 | instance = new DoubleCheckedLockingSingleton(); 27 | } 28 | } 29 | } 30 | return instance; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/executors/CompletionServiceExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.*; 6 | 7 | /** 8 | * Demonstrates the usage of ExecutorCompletionService for managing and retrieving 9 | * the results of asynchronous tasks. 10 | */ 11 | public class CompletionServiceExample { 12 | private final ExecutorService executorService = Executors.newFixedThreadPool(10); 13 | private final CompletionService completionService = new ExecutorCompletionService<>(executorService); 14 | 15 | /** 16 | * Submits a list of callable tasks to the executor and processes their results 17 | * as they complete. 18 | * 19 | * @param tasks A list of Callable tasks to be executed. 20 | * @throws InterruptedException If the current thread is interrupted while waiting. 21 | * @throws ExecutionException If a task computation threw an exception. 22 | */ 23 | public void executeTasks(List> tasks) throws InterruptedException, ExecutionException { 24 | // Submit all tasks 25 | for (Callable task : tasks) { 26 | completionService.submit(task); 27 | } 28 | 29 | // Retrieve and print the results as they complete 30 | for (int i = 0; i < tasks.size(); i++) { 31 | Future future = completionService.take(); // Blocks until a result is available 32 | System.out.println("Result: " + future.get()); 33 | } 34 | 35 | shutdown(); 36 | } 37 | 38 | /** 39 | * Shuts down the executor service. 40 | */ 41 | private void shutdown() { 42 | executorService.shutdown(); 43 | } 44 | 45 | public static void main(String[] args) throws InterruptedException, ExecutionException { 46 | CompletionServiceExample example = new CompletionServiceExample(); 47 | 48 | List> tasks = new ArrayList<>(); 49 | for (int i = 0; i < 10; i++) { 50 | final int taskId = i; 51 | tasks.add(() -> { 52 | Thread.sleep((int) (Math.random() * 1000)); 53 | return "Task " + taskId + " completed"; 54 | }); 55 | } 56 | 57 | example.executeTasks(tasks); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/executors/ExecutorServiceExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * The ExecutorServiceExample class demonstrates the usage of an ExecutorService 8 | * with a fixed thread pool size to execute multiple tasks concurrently. 9 | */ 10 | public class ExecutorServiceExample { 11 | /** 12 | * The main method creates an ExecutorService with a fixed thread pool size of 3 13 | * and submits tasks to it. Each task simulates some execution time and prints 14 | * its completion status along with the thread name. 15 | * 16 | * @param args The command-line arguments (unused). 17 | */ 18 | public static void main(String[] args) { 19 | // Create an ExecutorService with a fixed thread pool size of 3 20 | ExecutorService executorService = Executors.newFixedThreadPool(3); 21 | 22 | // Submit tasks to the ExecutorService 23 | for (int i = 0; i < 5; i++) { 24 | final int taskId = i; 25 | executorService.submit(() -> { 26 | try { 27 | // Simulate some task execution 28 | System.out.println("Task " + taskId + " is running on thread: " + Thread.currentThread().getName()); 29 | Thread.sleep(2000); 30 | System.out.println("Task " + taskId + " completed"); 31 | } catch (InterruptedException e) { 32 | Thread.currentThread().interrupt(); 33 | } 34 | }); 35 | } 36 | 37 | // Shutdown the ExecutorService 38 | executorService.shutdown(); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/executors/ScheduledThreadPoolExecutorExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import java.util.concurrent.ScheduledThreadPoolExecutor; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Demonstrates the usage of ScheduledThreadPoolExecutor to schedule tasks. 8 | */ 9 | public class ScheduledThreadPoolExecutorExample { 10 | 11 | /** 12 | * 13 | * We create a ScheduledThreadPoolExecutor with 3 threads. 14 | * We schedule three different tasks: 15 | * Task 1: Executes after a delay of 1 second using schedule(). 16 | * Task 2: Executes repeatedly with a fixed rate, starting after an initial delay of 2 seconds, with a period of 3 seconds using scheduleAtFixedRate(). 17 | * Task 3: Executes repeatedly with a fixed delay between termination of one execution and commencement of the next, starting after an initial delay of 2 seconds, with a delay of 3 seconds using scheduleWithFixedDelay(). 18 | * Finally, we schedule a task to shut down the executor after 10 seconds using schedule(). 19 | * 20 | */ 21 | public static void main(String[] args) { 22 | // Create a ScheduledThreadPoolExecutor with 3 threads 23 | ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3); 24 | 25 | // Schedule a task to run after a delay of 1 second 26 | executor.schedule(() -> { 27 | System.out.println("Task 1 executed after 1 second."); 28 | }, 1, TimeUnit.SECONDS); 29 | 30 | // Schedule a task to run repeatedly with an initial delay of 2 seconds and a period of 3 seconds 31 | executor.scheduleAtFixedRate(() -> { 32 | System.out.println("Task 2 executed repeatedly with a fixed rate."); 33 | }, 2, 3, TimeUnit.SECONDS); 34 | 35 | // Schedule a task to run repeatedly with an initial delay of 2 seconds and a delay between termination of one execution and commencement of the next 36 | executor.scheduleWithFixedDelay(() -> { 37 | System.out.println("Task 3 executed repeatedly with a fixed delay."); 38 | }, 2, 3, TimeUnit.SECONDS); 39 | 40 | // Shutdown the executor after 10 seconds 41 | executor.schedule(() -> { 42 | System.out.println("Shutting down the executor..."); 43 | executor.shutdown(); 44 | }, 10, TimeUnit.SECONDS); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/executors/ThreadPoolExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * Manages a pool of worker threads to perform tasks concurrently. 8 | * The ThreadPoolExample class demonstrates the use of an ExecutorService to manage a fixed thread pool. 9 | */ 10 | public class ThreadPoolExample { 11 | /** 12 | * The main method of the example program. 13 | * Creates a fixed thread pool with 10 threads and submits 20 tasks to be executed concurrently. 14 | * The ExecutorService is then shut down to stop accepting new tasks. 15 | * 16 | * @param args The command-line arguments (unused). 17 | */ 18 | public static void main(String[] args) { 19 | ExecutorService executorService = Executors.newFixedThreadPool(10); // Create a fixed thread pool with 10 threads 20 | for (int i = 0; i < 20; i++) { 21 | executorService.execute(new Task(i)); // Submit 20 tasks to the executor service 22 | } 23 | executorService.shutdown(); // Shut down the executor service 24 | } 25 | } 26 | 27 | /** 28 | * Represents a task that can be executed by a thread. 29 | * The Task class implements the Runnable interface and prints its task ID and the name of the executing thread. 30 | */ 31 | class Task implements Runnable { 32 | private int taskId; // The ID of the task 33 | 34 | /** 35 | * Constructs a new Task with the specified task ID. 36 | * 37 | * @param taskId The ID of the task. 38 | */ 39 | public Task(int taskId) { 40 | this.taskId = taskId; 41 | } 42 | 43 | /** 44 | * The run method contains the code to be executed when the task is run. 45 | * It prints the task ID and the name of the thread that is executing the task. 46 | */ 47 | @Override 48 | public void run() { 49 | System.out.println("Task ID : " + this.taskId + " performed by " + Thread.currentThread().getName()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/executors/ThreadPoolExecutorExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import java.util.concurrent.ThreadPoolExecutor; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * Demonstrates the usage of ThreadPoolExecutor to execute tasks. 8 | */ 9 | public class ThreadPoolExecutorExample { 10 | /** 11 | * We create a ThreadPoolExecutor with a core pool size of 2, maximum pool size of 4, and a queue capacity of 10. 12 | * We submit 10 tasks to the executor using the submit() method. 13 | * Each task prints its ID and the name of the thread executing it, simulating a task execution time of 1 second. 14 | * Finally, we shut down the executor using the shutdown() method. 15 | */ 16 | public static void main(String[] args) { 17 | // Create a ThreadPoolExecutor with a core pool size of 2, maximum pool size of 4, and a queue capacity of 10 18 | ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue<>(10)); 19 | 20 | // Submit tasks to the executor 21 | for (int i = 0; i < 10; i++) { 22 | final int taskId = i; 23 | executor.submit(() -> { 24 | System.out.println("Task " + taskId + " executed by thread: " + Thread.currentThread().getName()); 25 | try { 26 | Thread.sleep(1000); // Simulate task execution time 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | }); 31 | } 32 | 33 | // Shutdown the executor 34 | executor.shutdown(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/forkjoinpool/ForkJoinPoolExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.forkjoinpool; 2 | 3 | import java.util.concurrent.ForkJoinPool; 4 | import java.util.concurrent.RecursiveTask; 5 | 6 | public class ForkJoinPoolExample { 7 | 8 | public static void main(String[] args) { 9 | ForkJoinPool forkJoinPool = new ForkJoinPool(4); // 4 parallel threads 10 | MyRecursiveTask task = new MyRecursiveTask(100); 11 | Integer result = forkJoinPool.invoke(task); 12 | System.out.println("Result: " + result); 13 | } 14 | } 15 | 16 | class MyRecursiveTask extends RecursiveTask { 17 | private int workload; 18 | 19 | MyRecursiveTask(int workload) { 20 | this.workload = workload; 21 | } 22 | 23 | @Override 24 | protected Integer compute() { 25 | if (workload > 16) { 26 | MyRecursiveTask subtask1 = new MyRecursiveTask(workload / 2); 27 | MyRecursiveTask subtask2 = new MyRecursiveTask(workload / 2); 28 | 29 | subtask1.fork(); 30 | subtask2.fork(); 31 | 32 | int result = subtask1.join() + subtask2.join(); 33 | return result; 34 | } else { 35 | return workload * workload; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/future/FutureExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.future; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | 9 | /** 10 | * The FutureExample class demonstrates the usage of the Future interface 11 | * to represent the result of an asynchronous computation. 12 | */ 13 | public class FutureExample { 14 | 15 | /** 16 | * The main method creates an ExecutorService with a single thread, 17 | * submits a task to the executor, and retrieves the result from the Future. 18 | * It then prints the result and shuts down the executor. 19 | * 20 | * @param args The command-line arguments (unused). 21 | */ 22 | public static void main(String[] args) { 23 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 24 | Future future = executorService.submit(new Task()); 25 | 26 | try { 27 | System.out.println("Result from future: " + future.get()); 28 | } catch (InterruptedException | ExecutionException e) { 29 | e.printStackTrace(); 30 | } finally { 31 | executorService.shutdown(); 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * The Task class implements the Callable interface and represents a task 38 | * that computes a result asynchronously. 39 | */ 40 | class Task implements Callable { 41 | 42 | /** 43 | * The call method is called by the ExecutorService to execute the task. 44 | * It returns the result of the computation. 45 | * 46 | * @return The result of the computation. 47 | * @throws Exception If an exception occurs during the computation. 48 | */ 49 | @Override 50 | public Integer call() throws Exception { 51 | return 123; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/guardedsuspension/GuardedSuspensionExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.guardedsuspension; 2 | 3 | /** 4 | * The GuardedSuspensionExample class demonstrates the Guarded Suspension pattern, 5 | * where a thread waits for a condition to become true before proceeding with an action. 6 | */ 7 | public class GuardedSuspensionExample { 8 | private boolean condition = false; 9 | 10 | /** 11 | * The awaitCondition method waits until the condition becomes true. 12 | * It synchronizes access to the condition variable and waits using the wait() method. 13 | */ 14 | public synchronized void awaitCondition() { 15 | while (!condition) { 16 | try { 17 | wait(); 18 | } catch (InterruptedException e) { 19 | Thread.currentThread().interrupt(); 20 | } 21 | } 22 | // Proceed with the action 23 | } 24 | 25 | /** 26 | * The signalCondition method sets the condition to true and notifies all waiting threads. 27 | * It synchronizes access to the condition variable and signals using the notifyAll() method. 28 | */ 29 | public synchronized void signalCondition() { 30 | condition = true; 31 | notifyAll(); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/immutable/Immutable.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.immutable; 2 | 3 | /** 4 | * The Immutable class ensures objects are immutable, 5 | * meaning their state cannot be modified after construction. 6 | * This makes them safe to share between threads without synchronization. 7 | */ 8 | public final class Immutable { 9 | private final int value; 10 | 11 | /** 12 | * Constructs an Immutable object with the specified value. 13 | * 14 | * @param value the value of the Immutable object 15 | */ 16 | public Immutable(int value) { 17 | this.value = value; 18 | } 19 | 20 | /** 21 | * Retrieves the value of the Immutable object. 22 | * 23 | * @return the value of the Immutable object 24 | */ 25 | public int getValue() { 26 | return value; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/locks/LockSupportExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.locks; 2 | 3 | import java.util.concurrent.locks.LockSupport; 4 | 5 | /** 6 | * Demonstrates the use of LockSupport for thread synchronization. 7 | * 8 | * LockSupportExample Class: The main class demonstrating the use of LockSupport. 9 | * Task Class: A nested static class implementing Runnable, which parks its thread and waits to be unparked. 10 | * Constructor: Takes a Thread to unpark (for demonstration purposes). 11 | * run() Method: Parks the thread using LockSupport.park() and waits to be unparked. 12 | * main() Method: 13 | * mainThread: The reference to the current (main) thread. 14 | * taskThread: A new thread running an instance of Task that parks itself. 15 | * Thread.sleep(1000): Simulates some work in the main thread before unparking the taskThread. 16 | * LockSupport.unpark(taskThread): Unparks the taskThread, allowing it to continue execution. 17 | */ 18 | public class LockSupportExample { 19 | 20 | /** 21 | * A task that parks the current thread and waits to be unparked. 22 | */ 23 | private static class Task implements Runnable { 24 | private Thread threadToUnpark; 25 | 26 | /** 27 | * Constructs a new Task. 28 | * 29 | * @param threadToUnpark The thread that will be unparked (for demonstration purposes). 30 | */ 31 | public Task(Thread threadToUnpark) { 32 | this.threadToUnpark = threadToUnpark; 33 | } 34 | 35 | @Override 36 | public void run() { 37 | System.out.println(Thread.currentThread().getName() + " is about to park."); 38 | LockSupport.park(); 39 | System.out.println(Thread.currentThread().getName() + " is unparked and continues execution."); 40 | } 41 | } 42 | 43 | /** 44 | * Main method that demonstrates parking and unparking of threads. 45 | * 46 | * @param args Command line arguments. 47 | */ 48 | public static void main(String[] args) { 49 | Thread mainThread = Thread.currentThread(); 50 | 51 | // Create and start a new thread that will park itself 52 | Thread taskThread = new Thread(new Task(mainThread), "TaskThread"); 53 | taskThread.start(); 54 | 55 | try { 56 | Thread.sleep(1000); // Simulate some work in the main thread 57 | } catch (InterruptedException e) { 58 | Thread.currentThread().interrupt(); 59 | } 60 | 61 | // Unpark the parked thread 62 | System.out.println("Main thread is about to unpark TaskThread."); 63 | LockSupport.unpark(taskThread); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/locks/ReadWriteLockExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.locks; 2 | 3 | import java.util.concurrent.locks.ReentrantReadWriteLock; 4 | 5 | /** 6 | * An example class demonstrating the usage of a ReadWriteLock for managing concurrent read and write access to a shared resource. 7 | */ 8 | public class ReadWriteLockExample { 9 | private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); // The ReentrantReadWriteLock for synchronization 10 | private int value; // The shared resource value 11 | 12 | /** 13 | * Writes a new value to the shared resource. 14 | * 15 | * @param newValue The new value to write. 16 | */ 17 | public void write(int newValue) { 18 | rwLock.writeLock().lock(); // Acquire the write lock 19 | try { 20 | value = newValue; // Write the new value 21 | } finally { 22 | rwLock.writeLock().unlock(); // Release the write lock 23 | } 24 | } 25 | 26 | /** 27 | * Reads the current value of the shared resource. 28 | * 29 | * @return The current value of the shared resource. 30 | */ 31 | public int read() { 32 | rwLock.readLock().lock(); // Acquire the read lock 33 | try { 34 | return value; // Read and return the current value 35 | } finally { 36 | rwLock.readLock().unlock(); // Release the read lock 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/locks/ReentrantReadWriteLockCounter.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.locks; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantReadWriteLock; 5 | 6 | /** 7 | * Separates read and write access to a shared resource to improve concurrency. 8 | * The ReentrantReadWriteLockCounter class provides methods for incrementing and 9 | * retrieving a counter value with separate locks for reading and writing. 10 | */ 11 | public class ReentrantReadWriteLockCounter { 12 | private int counter; // The shared counter value 13 | private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); // The ReentrantReadWriteLock for synchronization 14 | private final Lock readLock = rwLock.readLock(); // The read lock 15 | private final Lock writeLock = rwLock.writeLock(); // The write lock 16 | 17 | /** 18 | * Increments the counter value with exclusive write access. 19 | */ 20 | public void incrementCounter() { 21 | writeLock.lock(); // Acquire the write lock 22 | try { 23 | counter += 1; // Increment the counter 24 | } finally { 25 | writeLock.unlock(); // Release the write lock 26 | } 27 | } 28 | 29 | /** 30 | * Retrieves the current value of the counter with shared read access. 31 | * 32 | * @return The current value of the counter. 33 | */ 34 | public int getCounter() { 35 | readLock.lock(); // Acquire the read lock 36 | try { 37 | return counter; // Return the current value of the counter 38 | } finally { 39 | readLock.unlock(); // Release the read lock 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/locks/ReentrantReadWriteLockCounterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.locks; 2 | 3 | /** 4 | * An example demonstrating the usage of ReentrantReadWriteLockCounter to manage a shared counter 5 | * among multiple threads. 6 | */ 7 | public class ReentrantReadWriteLockCounterExample { 8 | /** 9 | * The main method of the example program. 10 | * 11 | * @param args The command-line arguments (unused). 12 | */ 13 | public static void main(String[] args) { 14 | ReentrantReadWriteLockCounter counter = new ReentrantReadWriteLockCounter(); // Create a new ReentrantReadWriteLockCounter instance 15 | int numThreads = 5; // Number of threads 16 | Thread[] threads = new Thread[numThreads]; // Array to hold threads 17 | 18 | // Create and start multiple threads to increment the counter 19 | for (int i = 0; i < numThreads; i++) { 20 | threads[i] = new Thread(() -> { 21 | for (int j = 0; j < 1000; j++) { 22 | counter.incrementCounter(); // Increment the counter in a loop 23 | } 24 | }); 25 | threads[i].start(); // Start the thread 26 | } 27 | 28 | // Wait for all threads to finish execution 29 | try { 30 | for (Thread thread : threads) { 31 | thread.join(); // Wait for each thread to finish 32 | } 33 | } catch (InterruptedException e) { 34 | e.printStackTrace(); 35 | } 36 | 37 | // Retrieve the final value of the counter and print it 38 | int finalCounterValue = counter.getCounter(); 39 | System.out.println("Final Counter Value: " + finalCounterValue); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/monitorobject/MonitorObject.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.monitorobject; 2 | 3 | /** 4 | * The MonitorObject class encapsulates a lock in an object 5 | * to provide thread-safe methods for accessing shared resources. 6 | */ 7 | public class MonitorObject { 8 | private final Object lock = new Object(); 9 | private int count = 0; 10 | 11 | /** 12 | * Increments the count in a thread-safe manner. 13 | */ 14 | public void increment() { 15 | synchronized (lock) { 16 | count++; 17 | } 18 | } 19 | 20 | /** 21 | * Retrieves the count in a thread-safe manner. 22 | * 23 | * @return the current count 24 | */ 25 | public int getCount() { 26 | synchronized (lock) { 27 | return count; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/multithreadedcontext/MultithreadedContext.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.multithreadedcontext; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * The MultithreadedContext class provides a thread-safe context for executing operations. 8 | */ 9 | public final class MultithreadedContext { 10 | private static final MultithreadedContext INSTANCE = new MultithreadedContext(); 11 | private final Lock lock = new ReentrantLock(); 12 | 13 | /** 14 | * Private constructor to prevent instantiation. 15 | */ 16 | private MultithreadedContext() {} 17 | 18 | /** 19 | * Returns the singleton instance of MultithreadedContext. 20 | * 21 | * @return the singleton instance 22 | */ 23 | public static MultithreadedContext getInstance() { 24 | return INSTANCE; 25 | } 26 | 27 | /** 28 | * Executes a Runnable operation in a thread-safe context. 29 | * 30 | * @param runnable the operation to be executed 31 | */ 32 | public void apply(Runnable runnable) { 33 | lock.lock(); 34 | try { 35 | runnable.run(); 36 | } finally { 37 | lock.unlock(); 38 | } 39 | } 40 | 41 | /** 42 | * Attempts to execute a Runnable operation in a thread-safe context without blocking. 43 | * If the lock is not available, the operation will not be executed. 44 | * 45 | * @param runnable the operation to be executed 46 | * @return true if the operation was executed successfully, false otherwise 47 | */ 48 | public boolean tryApply(Runnable runnable) { 49 | if (lock.tryLock()) { 50 | try { 51 | runnable.run(); 52 | return true; 53 | } finally { 54 | lock.unlock(); 55 | } 56 | } 57 | return false; 58 | } 59 | 60 | /** 61 | * Main method demonstrating the usage of MultithreadedContext. 62 | * 63 | * @param args command-line arguments (not used) 64 | */ 65 | public static void main(String[] args) { 66 | MultithreadedContext context = MultithreadedContext.getInstance(); 67 | 68 | Runnable operation = () -> { 69 | System.out.println("Thread-safe operation is performed."); 70 | }; 71 | 72 | context.apply(operation); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/mutex/MutexExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.mutex; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * A mutex (short for mutual exclusion) is a synchronization primitive used to protect shared resources 8 | * from concurrent access by multiple threads. 9 | * In Java, ReentrantLock from the java.util.concurrent.locks package is commonly used as a mutex. 10 | */ 11 | public class MutexExample { 12 | private final Lock lock = new ReentrantLock(); 13 | private int counter = 0; 14 | 15 | /** 16 | * Increments the counter in a thread-safe manner. 17 | */ 18 | public void increment() { 19 | lock.lock(); 20 | try { 21 | counter++; 22 | } finally { 23 | lock.unlock(); 24 | } 25 | } 26 | 27 | /** 28 | * Retrieves the current value of the counter. 29 | * 30 | * @return the current value of the counter 31 | */ 32 | public int getCounter() { 33 | return counter; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/oddevenprinter/OddEvenPrinter.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.oddevenprinter; 2 | 3 | /** 4 | * The OddEvenPrinter class demonstrates printing odd and even numbers in separate threads. 5 | * It synchronizes the printing process to ensure that odd and even numbers are printed in alternating order. 6 | */ 7 | public class OddEvenPrinter { 8 | private final Object lock = new Object(); 9 | private boolean isOddTurn = true; 10 | private final int limit = 10; 11 | private final StringBuilder printedOutput = new StringBuilder(); 12 | 13 | /** 14 | * Starts the threads for printing odd and even numbers. 15 | */ 16 | public void startPrinting() { 17 | Thread oddThread = new Thread(this::printOddNumbers); 18 | Thread evenThread = new Thread(this::printEvenNumbers); 19 | 20 | oddThread.setName("OddThread"); 21 | evenThread.setName("EvenThread"); 22 | 23 | evenThread.start(); 24 | oddThread.start(); 25 | 26 | try { 27 | oddThread.join(); 28 | evenThread.join(); 29 | } catch (InterruptedException e) { 30 | Thread.currentThread().interrupt(); 31 | } 32 | } 33 | 34 | private void printOddNumbers() { 35 | synchronized (lock) { 36 | for (int i = 1; i <= limit; i += 2) { 37 | try { 38 | while (!isOddTurn) { 39 | lock.wait(); 40 | } 41 | printedOutput.append(Thread.currentThread().getName()).append(": ").append(i).append("\n"); 42 | isOddTurn = false; 43 | lock.notify(); 44 | } catch (InterruptedException e) { 45 | Thread.currentThread().interrupt(); 46 | } 47 | } 48 | } 49 | } 50 | 51 | private void printEvenNumbers() { 52 | synchronized (lock) { 53 | for (int i = 2; i <= limit; i += 2) { 54 | try { 55 | while (isOddTurn) { 56 | lock.wait(); 57 | } 58 | printedOutput.append(Thread.currentThread().getName()).append(": ").append(i).append("\n"); 59 | isOddTurn = true; 60 | lock.notify(); 61 | } catch (InterruptedException e) { 62 | Thread.currentThread().interrupt(); 63 | } 64 | } 65 | } 66 | } 67 | 68 | /** 69 | * Retrieves the printed output containing the odd and even numbers. 70 | * 71 | * @return the printed output 72 | */ 73 | public String getPrintedOutput() { 74 | return printedOutput.toString(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/oddevenprinter/OddEvenPrinterExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.oddevenprinter; 2 | 3 | /** 4 | * The OddEvenPrinterExample class demonstrates printing odd and even numbers in separate threads without a dedicated printer class. 5 | * It synchronizes the printing process to ensure that odd and even numbers are printed in alternating order. 6 | */ 7 | public class OddEvenPrinterExample { 8 | private static final Object lock = new Object(); 9 | private static boolean isOddTurn = true; 10 | private static final int limit = 10; 11 | 12 | /** 13 | * Main method to start the odd and even threads for printing numbers. 14 | * 15 | * @param args command line arguments (not used) 16 | */ 17 | public static void main(String[] args) { 18 | Thread oddThread = new Thread(OddEvenPrinterExample::printOddNumbers); 19 | Thread evenThread = new Thread(OddEvenPrinterExample::printEvenNumbers); 20 | 21 | oddThread.setName("OddThread"); 22 | evenThread.setName("EvenThread"); 23 | 24 | evenThread.start(); 25 | oddThread.start(); 26 | } 27 | 28 | private static void printOddNumbers() { 29 | synchronized (lock) { 30 | for (int i = 1; i <= limit; i += 2) { 31 | try { 32 | while (!isOddTurn) { 33 | lock.wait(); 34 | } 35 | System.out.println(Thread.currentThread().getName() + ": " + i); 36 | isOddTurn = false; 37 | lock.notify(); 38 | } catch (InterruptedException e) { 39 | Thread.currentThread().interrupt(); 40 | } 41 | } 42 | } 43 | } 44 | 45 | private static void printEvenNumbers() { 46 | synchronized (lock) { 47 | for (int i = 2; i <= limit; i += 2) { 48 | try { 49 | while (isOddTurn) { 50 | lock.wait(); 51 | } 52 | System.out.println(Thread.currentThread().getName() + ": " + i); 53 | isOddTurn = true; 54 | lock.notify(); 55 | } catch (InterruptedException e) { 56 | Thread.currentThread().interrupt(); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/philosopher/PhilosopherWithLock.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.philosopher; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | 5 | /** 6 | * The PhilosopherWithLock class represents a philosopher in the dining philosophers problem 7 | * using locks to synchronize access to the forks. 8 | */ 9 | class PhilosopherWithLock extends Thread { 10 | private final int id; 11 | private final Lock leftFork; 12 | private final Lock rightFork; 13 | 14 | /** 15 | * Constructs a PhilosopherWithLock with the specified ID and left and right forks. 16 | * 17 | * @param id the ID of the philosopher 18 | * @param leftFork the lock representing the left fork 19 | * @param rightFork the lock representing the right fork 20 | */ 21 | public PhilosopherWithLock(int id, Lock leftFork, Lock rightFork) { 22 | this.id = id; 23 | this.leftFork = leftFork; 24 | this.rightFork = rightFork; 25 | } 26 | 27 | /** 28 | * Simulates the philosopher thinking. 29 | * 30 | * @throws InterruptedException if the thread is interrupted while sleeping 31 | */ 32 | private void think() throws InterruptedException { 33 | System.out.println("Philosopher " + id + " is thinking"); 34 | Thread.sleep((long) (Math.random() * 1000)); 35 | } 36 | 37 | /** 38 | * Simulates the philosopher eating. 39 | * 40 | * @throws InterruptedException if the thread is interrupted while sleeping 41 | */ 42 | private void eat() throws InterruptedException { 43 | System.out.println("Philosopher " + id + " is eating"); 44 | Thread.sleep((long) (Math.random() * 1000)); 45 | } 46 | 47 | /** 48 | * Picks up both forks. 49 | */ 50 | private void pickUpForks() { 51 | leftFork.lock(); 52 | rightFork.lock(); 53 | } 54 | 55 | /** 56 | * Puts down both forks. 57 | */ 58 | private void putDownForks() { 59 | rightFork.unlock(); 60 | leftFork.unlock(); 61 | } 62 | 63 | /** 64 | * The main behavior of the philosopher thread. 65 | */ 66 | @Override 67 | public void run() { 68 | try { 69 | while (true) { 70 | think(); 71 | pickUpForks(); 72 | eat(); 73 | putDownForks(); 74 | } 75 | } catch (InterruptedException e) { 76 | Thread.currentThread().interrupt(); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/philosopher/PhilosopherWithSemaphore.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.philosopher; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | /** 6 | * The PhilosopherWithSemaphore class represents a philosopher in the dining philosophers problem 7 | * using semaphores to control access to a limited number of resources. 8 | */ 9 | public class PhilosopherWithSemaphore extends Thread { 10 | private final Semaphore sem; 11 | private boolean full = false; 12 | private final String name; 13 | 14 | /** 15 | * Constructs a PhilosopherWithSemaphore with the specified semaphore and name. 16 | * 17 | * @param sem the semaphore controlling access to the resources 18 | * @param name the name of the philosopher 19 | */ 20 | public PhilosopherWithSemaphore(Semaphore sem, String name) { 21 | this.sem = sem; 22 | this.name = name; 23 | } 24 | 25 | /** 26 | * The behavior of the philosopher thread. 27 | */ 28 | public void run() { 29 | try { 30 | if (!full) { 31 | sem.acquire(); 32 | System.out.println(name + " preparing"); 33 | sleep(300); // Simulating some work 34 | full = true; 35 | System.out.println(name + " finished"); 36 | sem.release(); 37 | sleep(300); // Simulating some work 38 | } 39 | } catch (InterruptedException e) { 40 | System.out.println("An error occurred"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/queue/ArrayBlockingQueueExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.queue; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | 6 | /** 7 | * The ArrayBlockingQueueExample class demonstrates the usage of a blocking queue, specifically an ArrayBlockingQueue. 8 | * It provides methods to produce and consume elements from the queue. 9 | */ 10 | public class ArrayBlockingQueueExample { 11 | private final BlockingQueue queue = new ArrayBlockingQueue<>(5); 12 | 13 | /** 14 | * Produces an integer value and puts it into the blocking queue. 15 | * 16 | * @param value The value to be produced and put into the queue. 17 | * @throws InterruptedException If the thread is interrupted while waiting to put the value into the queue. 18 | */ 19 | public void produce(int value) throws InterruptedException { 20 | queue.put(value); 21 | } 22 | 23 | /** 24 | * Consumes an integer value from the blocking queue. 25 | * 26 | * @return The consumed value from the queue. 27 | * @throws InterruptedException If the thread is interrupted while waiting to take a value from the queue. 28 | */ 29 | public Integer consume() throws InterruptedException { 30 | return queue.take(); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/reentrantlock/ReentrantLockCounter.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.reentrantlock; 2 | 3 | import java.util.concurrent.locks.ReentrantLock; 4 | 5 | /** 6 | * A simple counter implementation using a ReentrantLock for synchronization. 7 | * The ReentrantLockCounter class provides methods for incrementing and 8 | * retrieving a counter value with exclusive locking. 9 | */ 10 | public class ReentrantLockCounter { 11 | private final ReentrantLock lock = new ReentrantLock(); // The ReentrantLock for synchronization 12 | private int counter; // The shared counter value 13 | 14 | /** 15 | * Increments the counter value with exclusive locking. 16 | */ 17 | public void incrementCounter() { 18 | lock.lock(); // Acquire the lock 19 | try { 20 | counter++; // Increment the counter 21 | } finally { 22 | lock.unlock(); // Release the lock 23 | } 24 | } 25 | 26 | /** 27 | * Retrieves the current value of the counter. 28 | * 29 | * @return The current value of the counter. 30 | */ 31 | public int getCounter() { 32 | return counter; // Return the current value of the counter 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/reentrantlock/ReentrantLockExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.reentrantlock; 2 | 3 | /** 4 | * An example demonstrating the usage of ReentrantLockCounter to manage a shared counter 5 | * among multiple threads in a multithreaded environment. 6 | */ 7 | public class ReentrantLockExample { 8 | /** 9 | * The main method of the example program. 10 | * 11 | * @param args The command-line arguments (unused). 12 | * @throws InterruptedException If any thread is interrupted while sleeping. 13 | */ 14 | public static void main(String[] args) throws InterruptedException { 15 | ReentrantLockCounter reentrantLockCounter = new ReentrantLockCounter(); // Create a new ReentrantLockCounter instance 16 | 17 | // Create and start multiple threads to increment the counter concurrently 18 | for (int i = 0; i < 100; i++) { 19 | new Thread(reentrantLockCounter::incrementCounter).start(); // Start a new thread to increment the counter 20 | } 21 | 22 | // Sleep for 5 seconds to allow all threads to finish execution 23 | Thread.sleep(5000); 24 | 25 | // Retrieve and print the final value of the counter 26 | System.out.println(reentrantLockCounter.getCounter()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/scheduler/Scheduler.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.scheduler; 2 | 3 | import java.util.concurrent.Executors; 4 | import java.util.concurrent.ScheduledExecutorService; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * Allows scheduling tasks to be executed at a later point in time or periodically. 9 | * The Scheduler class provides methods for scheduling tasks to be executed after 10 | * a specified delay or at regular intervals. 11 | */ 12 | public class Scheduler { 13 | private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); // The ScheduledExecutorService for scheduling tasks 14 | 15 | /** 16 | * Schedules a task to be executed after a specified delay. 17 | * 18 | * @param task The task to be executed. 19 | * @param delay The delay before the task is executed. 20 | * @param unit The time unit of the delay parameter. 21 | */ 22 | public void schedule(Runnable task, long delay, TimeUnit unit) { 23 | scheduledExecutorService.schedule(task, delay, unit); // Schedule the task 24 | } 25 | 26 | /** 27 | * Shuts down the scheduler, preventing new tasks from being submitted. 28 | * Any previously submitted tasks will continue to execute. 29 | */ 30 | public void shutdown() { 31 | scheduledExecutorService.shutdown(); // Shutdown the scheduler 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/semaphore/SemaphoreExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.semaphore; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | /** 6 | * Limits the number of threads that can access a resource. 7 | * The SemaphoreExample class demonstrates the usage of a Semaphore to control access to a shared resource 8 | * by limiting the number of concurrent threads that can access it. 9 | */ 10 | public class SemaphoreExample { 11 | private final Semaphore semaphore = new Semaphore(3); // The Semaphore with an initial permit count of 3 12 | 13 | /** 14 | * Accesses the shared resource, acquiring a permit from the semaphore. 15 | * If no permits are available, the method blocks until a permit becomes available. 16 | * Once access is obtained, the method simulates resource access by sleeping for a short duration. 17 | */ 18 | public void accessResource() { 19 | try { 20 | semaphore.acquire(); // Acquire a permit 21 | // Simulate resource access 22 | Thread.sleep(100); // Simulate resource access for 100 milliseconds 23 | } catch (InterruptedException e) { 24 | Thread.currentThread().interrupt(); 25 | } finally { 26 | semaphore.release(); // Release the permit 27 | } 28 | } 29 | 30 | /** 31 | * Retrieves the number of permits currently available in the semaphore. 32 | * 33 | * @return The number of available permits. 34 | */ 35 | public int getAvailablePermits() { 36 | return semaphore.availablePermits(); // Return the number of available permits 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/singleton/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.singleton; 2 | 3 | /** 4 | * Ensures that a class has only one instance and provides a global point of access to it. 5 | * The Singleton class demonstrates the Singleton design pattern with lazy initialization and thread safety. 6 | */ 7 | public class Singleton { 8 | // The singleton instance, declared as volatile to ensure visibility of changes to variables across threads 9 | private static volatile Singleton instance; 10 | 11 | // Private constructor to prevent instantiation 12 | private Singleton() { 13 | } 14 | 15 | /** 16 | * Returns the singleton instance of the Singleton class. 17 | * This method uses double-checked locking to ensure that only one instance of the class is created, 18 | * and it is thread-safe. 19 | * 20 | * @return The singleton instance. 21 | */ 22 | public static Singleton getInstance() { 23 | if (instance == null) { // First check (no locking) 24 | synchronized (Singleton.class) { // Lock on the class object 25 | if (instance == null) { // Second check (with locking) 26 | instance = new Singleton(); // Create the singleton instance 27 | } 28 | } 29 | } 30 | return instance; // Return the singleton instance 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/Barrier.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.BrokenBarrierException; 4 | import java.util.concurrent.CyclicBarrier; 5 | 6 | /** 7 | * The Barrier class provides a synchronization mechanism that allows threads to synchronize at a certain 8 | * point to ensure all threads reach that point before proceeding. It encapsulates a CyclicBarrier instance 9 | * and provides a method for threads to await the barrier. 10 | */ 11 | public class Barrier { 12 | private final CyclicBarrier barrier; 13 | 14 | /** 15 | * Constructs a Barrier with the specified number of threads and barrier action. 16 | * 17 | * @param numThreads The number of threads to synchronize at the barrier. 18 | * @param barrierAction The action to be executed when all threads reach the barrier. 19 | */ 20 | public Barrier(int numThreads, Runnable barrierAction) { 21 | barrier = new CyclicBarrier(numThreads, barrierAction); 22 | } 23 | 24 | /** 25 | * Waits until all parties have invoked await on this barrier. 26 | * 27 | * @throws InterruptedException If the current thread is interrupted while waiting. 28 | * @throws BrokenBarrierException If the barrier is reset while any thread is waiting. 29 | */ 30 | public void await() throws InterruptedException, BrokenBarrierException { 31 | barrier.await(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/BarrierExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.BrokenBarrierException; 4 | import java.util.concurrent.CyclicBarrier; 5 | 6 | /** 7 | * The BarrierExample class demonstrates the usage of the CyclicBarrier class to synchronize multiple threads 8 | * at a certain point, ensuring they all reach that point before proceeding. 9 | */ 10 | public class BarrierExample { 11 | private static final int THREAD_COUNT = 3; 12 | private static final CyclicBarrier BARRIER = new CyclicBarrier(THREAD_COUNT, () -> System.out.println("All threads have reached the barrier, continuing...")); 13 | 14 | /** 15 | * The main method starts multiple threads and demonstrates how they synchronize at the barrier. 16 | * 17 | * @param args The command line arguments (not used in this example). 18 | * @throws InterruptedException If any thread is interrupted while waiting. 19 | */ 20 | public static void main(String[] args) throws InterruptedException { 21 | Runnable task = () -> { 22 | System.out.println(Thread.currentThread().getName() + " started"); 23 | try { 24 | // Simulating some work 25 | Thread.sleep(1000); 26 | 27 | System.out.println(Thread.currentThread().getName() + " is waiting at the barrier"); 28 | // The await() method causes the current thread to wait until all threads reach this point 29 | BARRIER.await(); 30 | System.out.println(Thread.currentThread().getName() + " passed the barrier"); 31 | 32 | // More work after passing the barrier 33 | } catch (InterruptedException | BrokenBarrierException e) { 34 | e.printStackTrace(); 35 | } 36 | }; 37 | 38 | // Starting THREAD_COUNT threads 39 | for (int i = 0; i < THREAD_COUNT; i++) { 40 | new Thread(task).start(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/CountDownLatchExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | /** 6 | * The CountDownLatchExample class demonstrates the usage of CountDownLatch, which is a synchronization aid that allows 7 | * one or more threads to wait until a set of operations being performed in other threads completes. It is useful for 8 | * scenarios where you want a thread to wait for other threads to complete certain tasks before proceeding. 9 | */ 10 | public class CountDownLatchExample { 11 | private final CountDownLatch latch; 12 | 13 | /** 14 | * Constructs a CountDownLatchExample with the given count. 15 | * 16 | * @param count The number of times the {@link #performTask()} method must be invoked before threads waiting 17 | * at the latch are released. 18 | */ 19 | public CountDownLatchExample(int count) { 20 | this.latch = new CountDownLatch(count); 21 | } 22 | 23 | /** 24 | * Simulates the completion of a task and decrements the latch count. 25 | */ 26 | public void performTask() { 27 | // Simulate task completion 28 | System.out.println(Thread.currentThread().getName() + " completed a task."); 29 | latch.countDown(); 30 | } 31 | 32 | /** 33 | * Causes the current thread to wait until the latch count reaches zero, indicating that all tasks have completed. 34 | * 35 | * @throws InterruptedException If the current thread is interrupted while waiting. 36 | */ 37 | public void waitForCompletion() throws InterruptedException { 38 | latch.await(); 39 | System.out.println("All tasks completed. Proceeding..."); 40 | } 41 | 42 | /** 43 | * Gets the CountDownLatch associated with this example. 44 | * 45 | * @return The CountDownLatch object. 46 | */ 47 | public CountDownLatch getLatch() { 48 | return latch; 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/ExchangerExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.Exchanger; 4 | 5 | /** 6 | * Demonstrates the usage of Exchanger for exchanging data between two threads. 7 | */ 8 | public class ExchangerExample { 9 | private final Exchanger exchanger = new Exchanger<>(); 10 | 11 | /** 12 | * Starts the data exchange process between two threads. 13 | */ 14 | public void start() throws InterruptedException { 15 | Thread producer = new Thread(new Producer()); 16 | Thread consumer = new Thread(new Consumer()); 17 | 18 | producer.start(); 19 | consumer.start(); 20 | 21 | producer.join(); 22 | consumer.join(); 23 | } 24 | 25 | /** 26 | * Producer class that exchanges data with the Consumer. 27 | */ 28 | private class Producer implements Runnable { 29 | @Override 30 | public void run() { 31 | try { 32 | String data = "Data from Producer"; 33 | System.out.println("Producer: " + data); 34 | String response = exchanger.exchange(data); 35 | System.out.println("Producer received: " + response); 36 | } catch (InterruptedException e) { 37 | Thread.currentThread().interrupt(); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * Consumer class that exchanges data with the Producer. 44 | */ 45 | private class Consumer implements Runnable { 46 | @Override 47 | public void run() { 48 | try { 49 | String data = "Data from Consumer"; 50 | System.out.println("Consumer: " + data); 51 | String response = exchanger.exchange(data); 52 | System.out.println("Consumer received: " + response); 53 | } catch (InterruptedException e) { 54 | Thread.currentThread().interrupt(); 55 | } 56 | } 57 | } 58 | 59 | public static void main(String[] args) throws InterruptedException { 60 | ExchangerExample example = new ExchangerExample(); 61 | example.start(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/PhaserExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.Phaser; 4 | 5 | /** 6 | * The CustomTask class represents a task to be executed in the PhaserExample. 7 | * Each task arrives at the phaser and then deregisters from it upon completion. 8 | */ 9 | class CustomTask implements Runnable { 10 | private final Phaser phaser; 11 | private final String taskName; 12 | 13 | /** 14 | * Constructs a CustomTask with the given phaser and task name. 15 | * 16 | * @param phaser the phaser to synchronize task execution 17 | * @param taskName the name of the task 18 | */ 19 | public CustomTask(Phaser phaser, String taskName) { 20 | this.phaser = phaser; 21 | this.taskName = taskName; 22 | phaser.register(); 23 | } 24 | 25 | @Override 26 | public void run() { 27 | System.out.println(taskName + " started"); 28 | phaser.arrive(); // Indicate that this task has arrived 29 | System.out.println(taskName + " completed"); 30 | phaser.arriveAndDeregister(); // Indicate that this task has completed and deregister from the phaser 31 | } 32 | } 33 | 34 | /** 35 | * The PhaserExample class demonstrates the usage of Phaser to synchronize multiple tasks. 36 | * It creates multiple threads, each representing a task, and waits for all tasks to complete using a Phaser. 37 | */ 38 | public class PhaserExample { 39 | public static void main(String[] args) { 40 | final int TASK_COUNT = 3; 41 | Phaser phaser = new Phaser(TASK_COUNT); // Create a Phaser with the specified number of parties 42 | 43 | // Create and start threads for each task 44 | for (int i = 1; i <= TASK_COUNT; i++) { 45 | String taskName = "Task " + i; 46 | new Thread(new CustomTask(phaser, taskName)).start(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/synchronizers/SemaphorePrintQueueExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | /** 6 | * Manages access to a print queue, limiting the number of concurrent print jobs. 7 | */ 8 | public class SemaphorePrintQueueExample { 9 | private final Semaphore semaphore; 10 | 11 | /** 12 | * Initializes the print queue with a specific number of permits. 13 | * 14 | * @param permits The number of concurrent accesses allowed. 15 | */ 16 | public SemaphorePrintQueueExample(int permits) { 17 | semaphore = new Semaphore(permits); 18 | } 19 | 20 | public Semaphore getSemaphore() { 21 | return semaphore; 22 | } 23 | 24 | /** 25 | * Simulates sending a print job to the print queue. 26 | * 27 | * @param jobName The name of the print job. 28 | */ 29 | public void printJob(String jobName) { 30 | try { 31 | semaphore.acquire(); 32 | System.out.println(Thread.currentThread().getName() + " is printing: " + jobName); 33 | Thread.sleep(2000); // Simulate time taken to print 34 | } catch (InterruptedException e) { 35 | Thread.currentThread().interrupt(); 36 | } finally { 37 | System.out.println(Thread.currentThread().getName() + " has finished printing: " + jobName); 38 | semaphore.release(); 39 | } 40 | } 41 | 42 | public static void main(String[] args) { 43 | SemaphorePrintQueueExample semaphorePrintQueueExample = new SemaphorePrintQueueExample(3); // Allow up to 3 concurrent print jobs 44 | 45 | Runnable printTask = () -> { 46 | String jobName = "Job-" + Thread.currentThread().getId(); 47 | semaphorePrintQueueExample.printJob(jobName); 48 | }; 49 | 50 | // Create and start 10 threads to simulate 10 print jobs 51 | for (int i = 0; i < 10; i++) { 52 | new Thread(printTask).start(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/threadlocal/ThreadLocalExample.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.threadlocal; 2 | 3 | /** 4 | * Provides each thread with its own instance of a class. 5 | * The ThreadSpecificStorageExample class demonstrates the use of ThreadLocal to give each thread its own instance of a variable. 6 | */ 7 | public class ThreadLocalExample { 8 | // ThreadLocal variable to store an Integer instance for each thread 9 | public static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(() -> 0); 10 | 11 | /** 12 | * The main method of the example program. 13 | * 14 | * @param args The command-line arguments (unused). 15 | */ 16 | public static void main(String[] args) { 17 | // Create and start the first thread 18 | Thread t1 = new Thread(() -> { 19 | THREAD_LOCAL.set(1); // Set the ThreadLocal value for this thread 20 | System.out.println("Thread 1: " + THREAD_LOCAL.get()); // Print the ThreadLocal value 21 | }); 22 | 23 | // Create and start the second thread 24 | Thread t2 = new Thread(() -> { 25 | THREAD_LOCAL.set(2); // Set the ThreadLocal value for this thread 26 | System.out.println("Thread 2: " + THREAD_LOCAL.get()); // Print the ThreadLocal value 27 | }); 28 | 29 | t1.start(); // Start the first thread 30 | t2.start(); // Start the second thread 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/threadsafelazyinitialization/LazyInitialization.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.threadsafelazyinitialization; 2 | 3 | /** 4 | * Ensures a class's instance is lazily initialized in a thread-safe manner. 5 | * The LazyInitialization class demonstrates the Singleton design pattern using the Bill Pugh Singleton Design. 6 | */ 7 | public class LazyInitialization { 8 | // Private static inner class that contains the instance of the Singleton class. 9 | // When the LazyInitialization class is loaded, the Holder class is not loaded into memory and only when someone calls the getInstance method, this class gets loaded and creates the Singleton class instance. 10 | private static class Holder { 11 | private static final LazyInitialization INSTANCE = new LazyInitialization(); // The singleton instance 12 | } 13 | 14 | // Private constructor to prevent instantiation 15 | private LazyInitialization() { 16 | } 17 | 18 | /** 19 | * Returns the singleton instance of the LazyInitialization class. 20 | * This method uses the Bill Pugh Singleton Design, which leverages the Java language's guarantees about class initialization to ensure thread safety. 21 | * 22 | * @return The singleton instance. 23 | */ 24 | public static LazyInitialization getInstance() { 25 | return Holder.INSTANCE; // Return the singleton instance 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/alxkm/patterns/twophasetermination/TwoPhaseTermination.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.twophasetermination; 2 | 3 | /** 4 | * Provides a graceful way to terminate threads, ensuring that resources are properly released. 5 | * The TwoPhaseTermination class demonstrates a thread termination mechanism that allows for cleanup 6 | * before the thread fully terminates. 7 | */ 8 | public class TwoPhaseTermination extends Thread { 9 | private volatile boolean running = true; // Flag to control the running state of the thread 10 | 11 | /** 12 | * The run method contains the code to be executed by the thread. 13 | * It runs in a loop, simulating work by sleeping for 100 milliseconds, until the running flag is set to false. 14 | * If interrupted, it sets the interrupt flag again and proceeds to the cleanup. 15 | */ 16 | @Override 17 | public void run() { 18 | try { 19 | while (running) { 20 | // Simulate work 21 | Thread.sleep(100); 22 | } 23 | } catch (InterruptedException e) { 24 | Thread.currentThread().interrupt(); // Restore the interrupted status 25 | } finally { 26 | // Cleanup 27 | cleanup(); // Perform cleanup actions 28 | } 29 | } 30 | 31 | /** 32 | * Terminates the thread by setting the running flag to false and interrupting the thread. 33 | * This method allows the thread to exit the loop and perform cleanup before terminating. 34 | */ 35 | public void terminate() { 36 | running = false; // Set the running flag to false to exit the loop 37 | interrupt(); // Interrupt the thread if it is sleeping or waiting 38 | } 39 | 40 | /** 41 | * Performs cleanup actions before the thread terminates. 42 | * This method is called in the finally block of the run method to ensure that resources are properly released. 43 | */ 44 | private void cleanup() { 45 | System.out.println("Cleaning up resources..."); 46 | } 47 | } -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/activeobjects/ActiveObjectTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.activeobjects; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.alxkm.patterns.activeobject.ActiveObject; 5 | 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.Future; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class ActiveObjectTest { 12 | 13 | /** 14 | * This test method verifies the behavior of the ActiveObject class, which demonstrates the usage of the 15 | * active object design pattern. It creates an ActiveObject instance and invokes the sayHello method on it 16 | * with the argument "World". The method call returns a Future object representing the result of the computation. 17 | * The test verifies that the result obtained from the Future matches the expected string "Hello, World". 18 | * Finally, the active object is shut down to release any associated resources. 19 | */ 20 | @Test 21 | public void testActiveObject() throws ExecutionException, InterruptedException { 22 | ActiveObject activeObject = new ActiveObject(); 23 | Future future = activeObject.sayHello("World"); 24 | 25 | assertEquals("Hello, World", future.get()); 26 | activeObject.shutdown(); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/balking/BalkingPatternExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.balking; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 6 | 7 | public class BalkingPatternExampleTest { 8 | /** 9 | * This test method verifies the behavior of the Balking Pattern implementation. 10 | * Specifically, it ensures that the `save` method in the `BalkingPatternExample` 11 | * class does not perform the save operation if the state has not changed since 12 | * the last save. 13 | */ 14 | @Test 15 | public void testBalkingPattern() { 16 | BalkingPatternExample example = new BalkingPatternExample(); 17 | example.change(); 18 | example.save(); 19 | // Method `save` should reset the dirty flag 20 | assertDoesNotThrow(example::save); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/collections/ConcurrentHashMapExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | public class ConcurrentHashMapExampleTest { 9 | 10 | /** 11 | * This test method verifies the behavior of the ConcurrentHashMapExample class, which demonstrates 12 | * the usage of the ConcurrentHashMap class for concurrent access. It creates 10 threads, each of 13 | * which adds a key-value pair to the ConcurrentHashMap instance concurrently. After all threads have 14 | * added their key-value pairs, the test checks that each key added by the threads is present in the map 15 | * and that the corresponding value matches the expected value. This test ensures that the ConcurrentHashMap 16 | * provides safe and consistent access for concurrent operations without the need for explicit synchronization. 17 | */ 18 | @Test 19 | public void testConcurrentHashMap() throws InterruptedException { 20 | ConcurrentHashMapExample example = new ConcurrentHashMapExample(); 21 | Thread[] threads = new Thread[10]; 22 | 23 | for (int i = 0; i < 10; i++) { 24 | final int index = i; 25 | threads[i] = new Thread(() -> { 26 | example.put("key" + index, index); 27 | assertTrue(example.containsKey("key" + index)); 28 | assertEquals(index, example.get("key" + index)); 29 | }); 30 | threads[i].start(); 31 | } 32 | 33 | for (Thread thread : threads) { 34 | thread.join(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/collections/ConcurrentSkipListSetExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | public class ConcurrentSkipListSetExampleTest { 9 | 10 | /** 11 | * This test method verifies the behavior of the ConcurrentSkipListSetExample class, which demonstrates 12 | * the usage of the ConcurrentSkipListSet class for concurrent access. It creates 10 threads, each of 13 | * which adds an element to the ConcurrentSkipListSet instance concurrently. After all threads have added 14 | * their elements, the test checks that each element added by the threads is present in the set. Then, 15 | * the test removes each element added by the threads and verifies that the set does not contain any of 16 | * these elements. This test ensures that the ConcurrentSkipListSet provides safe and consistent access 17 | * for concurrent operations without the need for explicit synchronization. 18 | */ 19 | @Test 20 | public void testConcurrentSkipListSet() throws InterruptedException { 21 | ConcurrentSkipListSetExample example = new ConcurrentSkipListSetExample(); 22 | Thread[] threads = new Thread[10]; 23 | 24 | for (int i = 0; i < 10; i++) { 25 | final int index = i; 26 | threads[i] = new Thread(() -> { 27 | example.add(index); 28 | assertTrue(example.contains(index)); 29 | }); 30 | threads[i].start(); 31 | } 32 | 33 | for (Thread thread : threads) { 34 | thread.join(); 35 | } 36 | 37 | for (int i = 0; i < 10; i++) { 38 | example.remove(i); 39 | assertFalse(example.contains(i)); 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/collections/CopyOnWriteArrayListExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | public class CopyOnWriteArrayListExampleTest { 9 | 10 | /** 11 | * This test method verifies the behavior of the CopyOnWriteArrayListExample class, which demonstrates 12 | * the usage of the CopyOnWriteArrayList class for concurrent access. It creates 10 threads, each of 13 | * which adds an element to the CopyOnWriteArrayList instance concurrently. After all threads have added 14 | * their elements, the test checks that each element added by the threads is present in the list. Then, 15 | * the test removes each element added by the threads and verifies that the list does not contain any of 16 | * these elements. This test ensures that the CopyOnWriteArrayList provides safe and consistent access 17 | * for concurrent operations without the need for explicit synchronization. 18 | */ 19 | @Test 20 | public void testCopyOnWriteArrayList() throws InterruptedException { 21 | CopyOnWriteArrayListExample example = new CopyOnWriteArrayListExample(); 22 | Thread[] threads = new Thread[10]; 23 | 24 | for (int i = 0; i < 10; i++) { 25 | final int index = i; 26 | threads[i] = new Thread(() -> { 27 | example.add("element" + index); 28 | assertTrue(example.contains("element" + index)); 29 | }); 30 | threads[i].start(); 31 | } 32 | 33 | for (Thread thread : threads) { 34 | thread.join(); 35 | } 36 | 37 | for (int i = 0; i < 10; i++) { 38 | example.remove("element" + i); 39 | assertFalse(example.contains("element" + i)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/doublechecklocking/DoubleCheckedLockingSingletonTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.doublechecklocking; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import static org.junit.jupiter.api.Assertions.assertSame; 9 | 10 | public class DoubleCheckedLockingSingletonTest { 11 | 12 | private static final int THREAD_COUNT = 1000; 13 | 14 | /** 15 | * This test method verifies the thread safety of the DoubleCheckedLockingSingleton class 16 | * in a highly concurrent multithreaded environment. It creates a large number of threads (THREAD_COUNT) 17 | * that concurrently attempt to retrieve an instance of DoubleCheckedLockingSingleton using the getInstance 18 | * method. The test ensures that all instances obtained by different threads are the same, verifying the 19 | * correctness of the double-checked locking mechanism in ensuring thread safety and preserving the singleton 20 | * property of the class under high concurrency. 21 | */ 22 | @Test 23 | public void testSingletonMultithreaded() throws InterruptedException { 24 | ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); 25 | CountDownLatch latch = new CountDownLatch(THREAD_COUNT); 26 | DoubleCheckedLockingSingleton[] instances = new DoubleCheckedLockingSingleton[THREAD_COUNT]; 27 | 28 | for (int i = 0; i < THREAD_COUNT; i++) { 29 | int index = i; 30 | executor.execute(() -> { 31 | instances[index] = DoubleCheckedLockingSingleton.getInstance(); 32 | latch.countDown(); 33 | }); 34 | } 35 | 36 | latch.await(); 37 | executor.shutdown(); 38 | 39 | for (int i = 1; i < THREAD_COUNT; i++) { 40 | assertSame(instances[0], instances[i], "All instances should be the same"); 41 | } 42 | } 43 | 44 | /** 45 | * This test method verifies the correctness of the DoubleCheckedLockingSingleton class, 46 | * ensuring that the getInstance method returns the same instance when called multiple times. 47 | * It obtains two instances of DoubleCheckedLockingSingleton using the getInstance method and 48 | * asserts that both instances are the same, confirming the singleton property of the class. 49 | */ 50 | @Test 51 | public void testDoubleCheckedLockingSingleton() { 52 | DoubleCheckedLockingSingleton instance1 = DoubleCheckedLockingSingleton.getInstance(); 53 | DoubleCheckedLockingSingleton instance2 = DoubleCheckedLockingSingleton.getInstance(); 54 | 55 | assertSame(instance1, instance2); 56 | } 57 | } -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/executors/CompletionServiceExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.concurrent.Callable; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | /** 12 | * Unit tests for the CompletionServiceExample class. 13 | */ 14 | public class CompletionServiceExampleTest { 15 | private CompletionServiceExample example; 16 | 17 | @BeforeEach 18 | public void setUp() { 19 | example = new CompletionServiceExample(); 20 | } 21 | 22 | @Test 23 | public void testExecuteTasks() throws InterruptedException, ExecutionException { 24 | List> tasks = new ArrayList<>(); 25 | for (int i = 0; i < 5; i++) { 26 | final int taskId = i; 27 | tasks.add(() -> { 28 | Thread.sleep((int) (Math.random() * 100)); 29 | return "Task " + taskId + " completed"; 30 | }); 31 | } 32 | 33 | // We cannot assert the exact order of completion because tasks complete asynchronously. 34 | // Instead, we focus on whether all tasks complete without throwing exceptions. 35 | example.executeTasks(tasks); 36 | } 37 | 38 | @Test 39 | public void testExecuteTasksWithCorrectResults() throws InterruptedException, ExecutionException { 40 | List> tasks = new ArrayList<>(); 41 | for (int i = 0; i < 3; i++) { 42 | final int taskId = i; 43 | tasks.add(() -> "Task " + taskId + " completed"); 44 | } 45 | 46 | example.executeTasks(tasks); 47 | 48 | // We could extend this test to verify output via capturing system output or refactoring to return results. 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/executors/ThreadPoolExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.executors; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | public class ThreadPoolExampleTest { 13 | 14 | /** 15 | * This test method verifies the execution of tasks in a thread pool using 16 | * the ExecutorService. It submits 20 tasks to a fixed thread pool of size 10, 17 | * each task simply decrements a CountDownLatch. It then shuts down the 18 | * executor service and waits for all tasks to complete within 1 second, 19 | * ensuring that all tasks executed successfully. 20 | */ 21 | @Test 22 | public void testThreadPoolExecution() throws InterruptedException { 23 | ExecutorService executorService = Executors.newFixedThreadPool(10); 24 | CountDownLatch latch = new CountDownLatch(20); 25 | 26 | for (int i = 0; i < 20; i++) { 27 | executorService.execute(() -> { 28 | latch.countDown(); 29 | }); 30 | } 31 | executorService.shutdown(); 32 | assertTrue(latch.await(1, TimeUnit.SECONDS)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/future/FutureExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.future; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.Future; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | public class FutureExampleTest { 13 | 14 | /** 15 | * This test method verifies the functionality of the FutureResult pattern, which allows 16 | * asynchronous execution of tasks and retrieval of their results. It creates a single-threaded 17 | * executor service and submits a task for execution. The test then waits for the task to complete 18 | * and retrieves the result using the Future object. Finally, the test asserts that the result obtained 19 | * from the Future matches the expected value (123) and shuts down the executor service. 20 | */ 21 | @Test 22 | public void testFutureResult() throws ExecutionException, InterruptedException { 23 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 24 | Future future = executorService.submit(new Task()); 25 | 26 | assertEquals(123, future.get()); 27 | executorService.shutdown(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/guardedsuspension/GuardedSuspensionExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.guardedsuspension; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | 7 | public class GuardedSuspensionExampleTest { 8 | 9 | /** 10 | * This test method verifies the behavior of the GuardedSuspensionExample class, which demonstrates 11 | * the Guarded Suspension pattern for coordinating communication between threads. It creates two threads, 12 | * t1 and t2, where t1 waits for a condition to be signaled by t2. The test ensures that t1 is waiting 13 | * for the condition by introducing a delay before starting t2. After both threads have completed their 14 | * execution or timed out, the test checks that neither thread is alive, confirming that both threads 15 | * have finished their respective tasks as expected. 16 | */ 17 | @Test 18 | public void testGuardedSuspension() throws InterruptedException { 19 | GuardedSuspensionExample example = new GuardedSuspensionExample(); 20 | Thread t1 = new Thread(example::awaitCondition); 21 | Thread t2 = new Thread(example::signalCondition); 22 | 23 | t1.start(); 24 | Thread.sleep(100); // Ensure t1 is waiting 25 | t2.start(); 26 | 27 | t1.join(1000); 28 | t2.join(1000); 29 | 30 | assertFalse(t1.isAlive()); 31 | assertFalse(t2.isAlive()); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/immutable/ImmutableTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.immutable; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class ImmutableTest { 8 | 9 | /** 10 | * This test method verifies the immutability of the Immutable class, which is designed to 11 | * encapsulate an immutable value. It creates an instance of the Immutable class with a value 12 | * of 42 and then asserts that the getValue method returns the expected value, ensuring that 13 | * the value set during object construction remains unchanged and immutable. 14 | */ 15 | @Test 16 | public void testImmutable() { 17 | Immutable immutable = new Immutable(42); 18 | 19 | assertEquals(42, immutable.getValue()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/monitorobject/MonitorObjectTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.monitorobject; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class MonitorObjectTest { 8 | 9 | /** 10 | * This test method verifies the behavior of the MonitorObject class, which demonstrates 11 | * the use of synchronization and mutual exclusion to protect shared resources in a multi-threaded 12 | * environment. It creates two threads, t1 and t2, both of which invoke the increment method 13 | * of the MonitorObject instance concurrently. The test ensures that both threads complete their 14 | * increments before checking the final count value. The expected count value after both threads 15 | * complete their increments is 2, indicating that the increment operation is properly synchronized 16 | * and the shared resource (count) is updated correctly by multiple threads. 17 | */ 18 | @Test 19 | public void testMonitorObject() throws InterruptedException { 20 | MonitorObject monitorObject = new MonitorObject(); 21 | Thread t1 = new Thread(monitorObject::increment); 22 | Thread t2 = new Thread(monitorObject::increment); 23 | 24 | t1.start(); 25 | t2.start(); 26 | 27 | t1.join(); 28 | t2.join(); 29 | 30 | assertEquals(2, monitorObject.getCount()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/mutex/MutexExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.mutex; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class MutexExampleTest { 12 | /** 13 | * The MutexExample class contains a ReentrantLock instance (lock) used to ensure mutual exclusion. 14 | * The increment method locks the mutex before incrementing the counter and unlocks it in a finally block to ensure the lock is always released. 15 | * The getCounter method returns the current value of counter. 16 | *

17 | * The test uses an ExecutorService with a fixed thread pool of 10 threads. 18 | * It submits 1000 tasks to increment the counter. 19 | * The shutdown method is called on the ExecutorService to stop accepting new tasks, and awaitTermination is used to wait for the completion of the submitted tasks. 20 | * Finally, the test verifies that the counter value is 1000, indicating that all increments were successful and no increments were lost due to concurrent access. 21 | */ 22 | @Test 23 | public void testMutex() throws InterruptedException { 24 | MutexExample mutexExample = new MutexExample(); 25 | ExecutorService executorService = Executors.newFixedThreadPool(10); 26 | 27 | // Submit 1000 increment tasks to the executor service 28 | for (int i = 0; i < 1000; i++) { 29 | executorService.submit(mutexExample::increment); 30 | } 31 | 32 | // Shutdown the executor service and wait for tasks to finish 33 | executorService.shutdown(); 34 | executorService.awaitTermination(1, TimeUnit.MINUTES); 35 | 36 | // Verify the counter value 37 | assertEquals(1000, mutexExample.getCounter()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/oddevenprinter/OddEvenPrinterTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.oddevenprinter; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class OddEvenPrinterTest { 8 | 9 | /** 10 | * This test method verifies the functionality of the OddEvenPrinter class, which implements a 11 | * solution to the classic Odd-Even printing problem using two separate threads. It starts the 12 | * printing process by invoking the startPrinting method of the OddEvenPrinter instance. After 13 | * allowing some time for the threads to finish printing, the test compares the printed output 14 | * against the expected output. The expected output contains alternating lines of numbers printed 15 | * by the OddThread and EvenThread threads, starting from 1. This test ensures that the OddEvenPrinter 16 | * class correctly prints odd and even numbers in sequence using two separate threads. 17 | */ 18 | @Test 19 | public void testOddEvenPrinter() throws InterruptedException { 20 | OddEvenPrinter oddEvenPrinter = new OddEvenPrinter(); 21 | oddEvenPrinter.startPrinting(); 22 | 23 | // Sleep for a while to allow threads to finish printing 24 | Thread.sleep(1000); 25 | 26 | String expectedOutput = 27 | "OddThread: 1\n" + 28 | "EvenThread: 2\n" + 29 | "OddThread: 3\n" + 30 | "EvenThread: 4\n" + 31 | "OddThread: 5\n" + 32 | "EvenThread: 6\n" + 33 | "OddThread: 7\n" + 34 | "EvenThread: 8\n" + 35 | "OddThread: 9\n" + 36 | "EvenThread: 10"; 37 | assertEquals(expectedOutput, oddEvenPrinter.getPrintedOutput().trim()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/philosopher/PhilosopherWithLockTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.philosopher; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | public class PhilosopherWithLockTest { 9 | 10 | /** 11 | * This test method verifies the behavior of the PhilosopherWithLock class, which implements 12 | * the Dining Philosophers problem solution using locks (ReentrantLocks). It creates a certain 13 | * number of philosopher threads (in this case, 5) and initializes an array of locks to represent 14 | * the forks on the table. Each philosopher thread represents a philosopher in the dining philosophers 15 | * scenario and is initialized with the corresponding left and right forks. The test runs the simulation 16 | * for a specified time duration (e.g., 5 seconds) to allow the philosophers to attempt to acquire forks 17 | * and eat. After the simulation period, all philosopher threads are interrupted to stop the simulation. 18 | * This test checks whether the Dining Philosophers problem solution using locks works as expected and 19 | * avoids deadlock and starvation scenarios. 20 | */ 21 | @Test 22 | public void testDiningPhilosophers() { 23 | int numOfPhilosophers = 5; 24 | PhilosopherWithLock[] philosopherWithLocks = new PhilosopherWithLock[numOfPhilosophers]; 25 | Lock[] forks = new Lock[numOfPhilosophers]; 26 | 27 | for (int i = 0; i < numOfPhilosophers; i++) { 28 | forks[i] = new ReentrantLock(); 29 | } 30 | 31 | for (int i = 0; i < numOfPhilosophers; i++) { 32 | philosopherWithLocks[i] = new PhilosopherWithLock(i, forks[i], forks[(i + 1) % numOfPhilosophers]); 33 | philosopherWithLocks[i].start(); 34 | } 35 | 36 | try { 37 | // Let the simulation run for a certain time (e.g., 5 seconds) in the test 38 | Thread.sleep(5000); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | 43 | // Interrupt all philosophers to stop the simulation after a certain time 44 | for (PhilosopherWithLock philosopherWithLock : philosopherWithLocks) { 45 | philosopherWithLock.interrupt(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/philosopher/PhilosopherWithSemaphoreTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.philosopher; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.Semaphore; 6 | 7 | public class PhilosopherWithSemaphoreTest { 8 | 9 | /** 10 | * This test method verifies the behavior of the PhilosopherWithSemaphore class, which implements 11 | * the Dining Philosophers problem solution using semaphores. It creates a certain number of philosopher 12 | * threads (in this case, 5) and initializes a semaphore with the maximum allowed number of concurrent 13 | * philosophers minus one (to avoid deadlock). Each philosopher thread represents a philosopher in the 14 | * dining philosophers scenario. The test runs the simulation for a specified time duration (e.g., 2 seconds) 15 | * to allow the philosophers to attempt to acquire forks and eat. After the simulation period, all philosopher 16 | * threads are interrupted to stop the simulation. This test checks whether the Dining Philosophers problem 17 | * solution using semaphores works as expected and avoids deadlock and starvation scenarios. 18 | */ 19 | @Test 20 | public void testPhilosophersWithSemaphore() { 21 | int numOfPhilosophers = 5; 22 | Semaphore semaphore = new Semaphore(numOfPhilosophers - 1); 23 | 24 | PhilosopherWithSemaphore[] philosophers = new PhilosopherWithSemaphore[numOfPhilosophers]; 25 | 26 | for (int i = 0; i < numOfPhilosophers; i++) { 27 | philosophers[i] = new PhilosopherWithSemaphore(semaphore, "Philosopher " + (i + 1)); 28 | philosophers[i].start(); 29 | } 30 | 31 | try { 32 | // Let the simulation run for a certain time (e.g., 2 seconds) in the test 33 | Thread.sleep(2000); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } 37 | 38 | // Interrupt all philosophers to stop the simulation after a certain time 39 | for (PhilosopherWithSemaphore philosopher : philosophers) { 40 | philosopher.interrupt(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/queue/ArrayBlockingQueueExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.queue; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertNotNull; 6 | 7 | public class ArrayBlockingQueueExampleTest { 8 | 9 | /** 10 | * This test method verifies the behavior of the ArrayBlockingQueueExample class, which demonstrates 11 | * the usage of the ArrayBlockingQueue class for producer-consumer synchronization. It creates a producer 12 | * thread that adds integers to the blocking queue and a consumer thread that consumes integers from the queue. 13 | * The producer thread produces integers from 0 to 9, while the consumer thread consumes them. The test ensures 14 | * that each produced integer is successfully consumed from the queue and that no null values are consumed, 15 | * indicating that the producer-consumer synchronization is working correctly. 16 | */ 17 | @Test 18 | public void testArrayBlockingQueue() throws InterruptedException { 19 | ArrayBlockingQueueExample example = new ArrayBlockingQueueExample(); 20 | Thread producer = new Thread(() -> { 21 | try { 22 | for (int i = 0; i < 10; i++) { 23 | example.produce(i); 24 | System.out.println("Produced: " + i); 25 | } 26 | } catch (InterruptedException e) { 27 | Thread.currentThread().interrupt(); 28 | } 29 | }); 30 | 31 | Thread consumer = new Thread(() -> { 32 | try { 33 | for (int i = 0; i < 10; i++) { 34 | Integer value = example.consume(); 35 | System.out.println("Consumed: " + value); 36 | assertNotNull(value); 37 | } 38 | } catch (InterruptedException e) { 39 | Thread.currentThread().interrupt(); 40 | } 41 | }); 42 | 43 | producer.start(); 44 | consumer.start(); 45 | 46 | producer.join(); 47 | consumer.join(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/queue/CustomBlockingQueueTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.queue; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | public class CustomBlockingQueueTest { 10 | 11 | /** 12 | * This test method verifies the functionality of the CustomBlockingQueue class, which implements 13 | * a blocking queue with a fixed capacity. It creates a CustomBlockingQueue instance with a capacity 14 | * of 5 and launches multiple producer and consumer threads. Each producer thread enqueues an item 15 | * into the queue, while each consumer thread dequeues an item from the queue. The test ensures that 16 | * all producer and consumer threads complete their operations by using CountDownLatch objects to 17 | * synchronize their execution. After all producer and consumer threads have finished, the test checks 18 | * that the size of the queue is 0, indicating that all items have been dequeued and the queue is empty. 19 | */ 20 | @Test 21 | void testBlockingQueue() throws InterruptedException { 22 | final int capacity = 5; 23 | final CustomBlockingQueue blockingQueue = new CustomBlockingQueue<>(capacity); 24 | final int numThreads = 10; 25 | 26 | final CountDownLatch producerLatch = new CountDownLatch(numThreads); 27 | final CountDownLatch consumerLatch = new CountDownLatch(numThreads); 28 | 29 | for (int i = 0; i < numThreads; i++) { 30 | new Thread(() -> { 31 | try { 32 | blockingQueue.enqueue(1); 33 | producerLatch.countDown(); 34 | } catch (InterruptedException e) { 35 | Thread.currentThread().interrupt(); 36 | } 37 | }).start(); 38 | } 39 | 40 | for (int i = 0; i < numThreads; i++) { 41 | new Thread(() -> { 42 | try { 43 | blockingQueue.dequeue(); 44 | consumerLatch.countDown(); 45 | } catch (InterruptedException e) { 46 | Thread.currentThread().interrupt(); 47 | } 48 | }).start(); 49 | } 50 | 51 | producerLatch.await(); 52 | consumerLatch.await(); 53 | 54 | assertEquals(0, blockingQueue.size(), "Queue should be empty after all items are dequeued"); 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/reactor/ReactorTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.reactor; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | 7 | import java.io.IOException; 8 | import java.net.Socket; 9 | 10 | public class ReactorTest { 11 | 12 | /** 13 | * This test method verifies the functionality of the Reactor class, which implements a simple reactor 14 | * pattern for handling incoming socket connections. It starts a Reactor instance on a separate thread, 15 | * then creates a socket and attempts to connect to the localhost on the specified port (12345). The test 16 | * asserts that the socket connection is successful by checking if the socket is connected. After the 17 | * connection is established, the socket is closed, and then the Reactor is stopped and the reactorThread 18 | * is joined to ensure proper termination. 19 | */ 20 | @Test 21 | public void testReactor() throws IOException, InterruptedException { 22 | Reactor reactor = new Reactor(12345); 23 | Thread reactorThread = new Thread(reactor); 24 | reactorThread.start(); 25 | 26 | Socket socket = new Socket("localhost", 12345); 27 | assertTrue(socket.isConnected()); 28 | socket.close(); 29 | 30 | reactor.stop(); 31 | reactorThread.join(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/readwritelock/ReentrantReadWriteLockCounterTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.readwritelock; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.alxkm.patterns.locks.ReadWriteLockExample; 5 | import org.alxkm.patterns.locks.ReentrantReadWriteLockCounter; 6 | 7 | import java.util.concurrent.CountDownLatch; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class ReentrantReadWriteLockCounterTest { 12 | 13 | /** 14 | * This test method verifies the concurrency behavior of the ReentrantReadWriteLockCounter class, 15 | * which implements a counter with thread-safe operations using ReentrantReadWriteLock. It creates 16 | * multiple threads (10 in this case), each incrementing the counter by a fixed amount (1000 in this 17 | * case). After all threads have completed their increments, the test checks whether the final value 18 | * of the counter matches the expected value, which is the total number of increments performed by 19 | * all threads combined. 20 | */ 21 | @Test 22 | void testCounterConcurrency() throws InterruptedException { 23 | final ReentrantReadWriteLockCounter counter = new ReentrantReadWriteLockCounter(); 24 | final int numThreads = 10; 25 | final int incrementsPerThread = 1000; 26 | 27 | final CountDownLatch latch = new CountDownLatch(numThreads); 28 | 29 | for (int i = 0; i < numThreads; i++) { 30 | new Thread(() -> { 31 | for (int j = 0; j < incrementsPerThread; j++) { 32 | counter.incrementCounter(); 33 | } 34 | latch.countDown(); 35 | }).start(); 36 | } 37 | 38 | latch.await(); 39 | 40 | final int expectedValue = numThreads * incrementsPerThread; 41 | final int counterValue = counter.getCounter(); 42 | assertEquals(expectedValue, counterValue, "The counter value should be equal to the expected value"); 43 | } 44 | 45 | /** 46 | * This test method verifies the functionality of the ReadWriteLockExample class, which demonstrates 47 | * the usage of ReadWriteLock to provide concurrent read access and exclusive write access to a shared 48 | * resource. It sets a value using the write method and then reads the value using the read method. 49 | * The test asserts that the value read from the shared resource matches the value previously written, 50 | * confirming that the read and write operations are performed correctly with the appropriate locking 51 | * mechanisms in place to ensure thread safety. 52 | */ 53 | 54 | @Test 55 | public void testReadWriteLock() throws InterruptedException { 56 | ReadWriteLockExample example = new ReadWriteLockExample(); 57 | example.write(42); 58 | assertEquals(42, example.read()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/scheduler/SchedulerTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.scheduler; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import java.util.concurrent.CountDownLatch; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | public class SchedulerTest { 10 | 11 | /** 12 | * This test method verifies the functionality of the Scheduler class for scheduling 13 | * tasks to run after a certain delay. It creates a Scheduler instance and a CountDownLatch 14 | * with an initial count of 1. The scheduler is then used to schedule a task that counts 15 | * down the latch after a delay of 1 second. The test waits for the latch to count down 16 | * within 2 seconds, ensuring that the scheduled task is executed within the expected time 17 | * frame. Finally, the scheduler is shut down to release any associated resources. 18 | */ 19 | @Test 20 | public void testScheduler() throws InterruptedException { 21 | Scheduler scheduler = new Scheduler(); 22 | CountDownLatch latch = new CountDownLatch(1); 23 | 24 | scheduler.schedule(latch::countDown, 1, TimeUnit.SECONDS); 25 | 26 | assertTrue(latch.await(2, TimeUnit.SECONDS)); 27 | scheduler.shutdown(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/singleton/DoubleCheckedLockingSingletonTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.singleton; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertSame; 6 | 7 | public class DoubleCheckedLockingSingletonTest { 8 | 9 | /** 10 | * This test method verifies that the Singleton pattern is correctly implemented 11 | * by ensuring that multiple calls to the getInstance method of the Singleton class 12 | * return the same instance. 13 | */ 14 | @Test 15 | public void testSingletonInstance() { 16 | Singleton instance1 = Singleton.getInstance(); 17 | Singleton instance2 = Singleton.getInstance(); 18 | 19 | assertSame(instance1, instance2); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/synchronizers/BarrierTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.BrokenBarrierException; 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class BarrierTest { 11 | 12 | /** 13 | * This test method verifies the behavior of the Barrier class, which implements a simple barrier 14 | * synchronization mechanism. It creates two threads, t1 and t2, both of which await on the barrier 15 | * before proceeding. The barrier is initialized with a count of 2, indicating that it should block 16 | * until two threads have arrived. Once both threads arrive at the barrier, the test ensures that the 17 | * latch count is decremented to 0, indicating that both threads have successfully passed through the barrier. 18 | */ 19 | @Test 20 | public void testBarrier() throws InterruptedException { 21 | CountDownLatch latch = new CountDownLatch(1); 22 | Barrier barrier = new Barrier(2, latch::countDown); 23 | 24 | Thread t1 = new Thread(() -> { 25 | try { 26 | barrier.await(); 27 | } catch (InterruptedException | BrokenBarrierException e) { 28 | Thread.currentThread().interrupt(); 29 | } 30 | }); 31 | 32 | Thread t2 = new Thread(() -> { 33 | try { 34 | barrier.await(); 35 | } catch (InterruptedException | BrokenBarrierException e) { 36 | Thread.currentThread().interrupt(); 37 | } 38 | }); 39 | 40 | t1.start(); 41 | t2.start(); 42 | 43 | t1.join(); 44 | t2.join(); 45 | 46 | assertEquals(0, latch.getCount()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/synchronizers/CountDownLatchExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class CountDownLatchExampleTest { 12 | 13 | /** 14 | * The CountDownLatchExample class has a CountDownLatch initialized with a given count. 15 | * The performTask method simulates task completion by printing a message and decrementing the latch count using countDown(). 16 | * The waitForCompletion method waits until the latch count reaches zero using await(), indicating that all tasks have completed. 17 | * The getLatch method provides access to the latch for testing purposes. 18 | *

19 | * The test initializes CountDownLatchExample with a task count of 5. 20 | * An ExecutorService with a fixed thread pool is used to submit tasks that perform work and count down the latch. 21 | * The waitForCompletion method is called to wait for all tasks to complete. 22 | * The test verifies that the latch count reached zero, ensuring all tasks were completed. 23 | * The ExecutorService is then shut down and awaits termination. 24 | */ 25 | @Test 26 | public void testCountDownLatch() throws InterruptedException { 27 | int taskCount = 5; 28 | CountDownLatchExample example = new CountDownLatchExample(taskCount); 29 | ExecutorService executorService = Executors.newFixedThreadPool(taskCount); 30 | 31 | // Submit tasks to the executor service 32 | for (int i = 0; i < taskCount; i++) { 33 | executorService.submit(example::performTask); 34 | } 35 | 36 | // Wait for all tasks to complete 37 | example.waitForCompletion(); 38 | 39 | // Verify that the latch count reached zero 40 | assertEquals(0, example.getLatch().getCount()); 41 | 42 | // Shutdown the executor service 43 | executorService.shutdown(); 44 | executorService.awaitTermination(1, TimeUnit.MINUTES); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/synchronizers/ExchangerExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.concurrent.Exchanger; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | /** 11 | * Unit tests for the ExchangerExample class. 12 | * 13 | * setUp(): Initializes a new instance of ExchangerExample before each test. 14 | * testExchanger(): Tests the overall exchange process by starting the producer and consumer threads. 15 | * testProducerConsumerExchange(): Tests the actual exchange of data between producer and consumer threads by asserting the exchanged values. 16 | */ 17 | public class ExchangerExampleTest { 18 | private ExchangerExample example; 19 | 20 | @BeforeEach 21 | public void setUp() { 22 | example = new ExchangerExample(); 23 | } 24 | 25 | @Test 26 | public void testExchanger() throws InterruptedException { 27 | // This test indirectly verifies the exchange process by starting the producer and consumer threads 28 | example.start(); 29 | } 30 | 31 | @Test 32 | public void testProducerConsumerExchange() throws InterruptedException { 33 | // This test verifies the actual exchange of data between producer and consumer 34 | Exchanger exchanger = new Exchanger<>(); 35 | Thread producer = new Thread(() -> { 36 | try { 37 | String data = "Data from Producer"; 38 | String response = exchanger.exchange(data); 39 | assertEquals("Data from Consumer", response); 40 | } catch (InterruptedException e) { 41 | Thread.currentThread().interrupt(); 42 | } 43 | }); 44 | 45 | Thread consumer = new Thread(() -> { 46 | try { 47 | String data = "Data from Consumer"; 48 | String response = exchanger.exchange(data); 49 | assertEquals("Data from Producer", response); 50 | } catch (InterruptedException e) { 51 | Thread.currentThread().interrupt(); 52 | } 53 | }); 54 | 55 | producer.start(); 56 | consumer.start(); 57 | 58 | producer.join(); 59 | consumer.join(); 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/synchronizers/SemaphorePrintQueueExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.synchronizers; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | import static org.junit.jupiter.api.Assertions.assertTrue; 12 | 13 | /** 14 | * Unit tests for the PrintQueue class. 15 | */ 16 | public class SemaphorePrintQueueExampleTest { 17 | private SemaphorePrintQueueExample semaphorePrintQueueExample; 18 | 19 | @BeforeEach 20 | public void setUp() { 21 | semaphorePrintQueueExample = new SemaphorePrintQueueExample(3); // Initialize with 3 permits 22 | } 23 | 24 | @Test 25 | public void testPrintJob() throws InterruptedException { 26 | ExecutorService executorService = Executors.newFixedThreadPool(10); 27 | 28 | // Submit 10 print jobs to the print queue 29 | for (int i = 0; i < 10; i++) { 30 | executorService.submit(() -> { 31 | String jobName = "Job-" + Thread.currentThread().getId(); 32 | semaphorePrintQueueExample.printJob(jobName); 33 | }); 34 | } 35 | 36 | executorService.shutdown(); 37 | boolean finished = executorService.awaitTermination(1, TimeUnit.MINUTES); 38 | assertTrue(finished, "Print jobs did not finish in time"); 39 | } 40 | 41 | @Test 42 | public void testSemaphoreLimits() throws InterruptedException { 43 | ExecutorService executorService = Executors.newFixedThreadPool(10); 44 | 45 | // Submit 10 print jobs to the print queue 46 | int max = 0; 47 | for (int i = 0; i < 3; i++) { 48 | executorService.submit(() -> { 49 | String jobName = "Job-" + Thread.currentThread().getId(); 50 | semaphorePrintQueueExample.printJob(jobName); 51 | }); 52 | max = Math.max(max, semaphorePrintQueueExample.getSemaphore().availablePermits()); 53 | } 54 | 55 | Thread.sleep(1000); // Short delay to allow some jobs to start 56 | assertEquals(3, max, "There should be 3 permits in use"); 57 | 58 | executorService.shutdown(); 59 | executorService.awaitTermination(1, TimeUnit.MINUTES); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/threadlocal/ThreadLocalExampleTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.threadlocal; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class ThreadLocalExampleTest { 8 | 9 | /** 10 | * This test method verifies the usage of ThreadLocal to maintain thread-specific 11 | * storage in the ThreadSpecificStorageExample class. It creates two threads, t1 and t2, 12 | * each of which sets a different value to the ThreadLocal variable in the example object. 13 | * The test asserts that each thread sees its own value when accessing the ThreadLocal 14 | * variable, ensuring that the values are maintained separately for each thread. 15 | */ 16 | @Test 17 | public void testThreadLocalStorage() throws InterruptedException { 18 | ThreadLocalExample example = new ThreadLocalExample(); 19 | 20 | Thread t1 = new Thread(() -> { 21 | example.THREAD_LOCAL.set(1); 22 | assertEquals(1, example.THREAD_LOCAL.get()); 23 | }); 24 | 25 | Thread t2 = new Thread(() -> { 26 | example.THREAD_LOCAL.set(2); 27 | assertEquals(2, example.THREAD_LOCAL.get()); 28 | }); 29 | 30 | t1.start(); 31 | t2.start(); 32 | 33 | t1.join(); 34 | t2.join(); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/threadsafelazyinitialization/LazyInitializationTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.threadsafelazyinitialization; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertSame; 6 | 7 | public class LazyInitializationTest { 8 | 9 | /** 10 | * This test method verifies the lazy initialization of a singleton instance 11 | * using the Lazy Initialization pattern. It ensures that multiple calls to 12 | * the getInstance method of the LazyInitialization class return the same instance. 13 | */ 14 | @Test 15 | public void testLazyInitialization() { 16 | LazyInitialization instance1 = LazyInitialization.getInstance(); 17 | LazyInitialization instance2 = LazyInitialization.getInstance(); 18 | 19 | assertSame(instance1, instance2); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/alxkm/patterns/twophasetermination/TwoPhaseTerminationTest.java: -------------------------------------------------------------------------------- 1 | package org.alxkm.patterns.twophasetermination; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | 7 | public class TwoPhaseTerminationTest { 8 | 9 | /** 10 | * This test method verifies the behavior of the Two-Phase Termination pattern implementation. 11 | * It ensures that a thread can be gracefully terminated using the Two-Phase Termination pattern. 12 | */ 13 | @Test 14 | public void testTwoPhaseTermination() throws InterruptedException { 15 | TwoPhaseTermination thread = new TwoPhaseTermination(); 16 | thread.start(); 17 | 18 | Thread.sleep(500); // Let the thread run for a while 19 | thread.terminate(); 20 | thread.join(); 21 | 22 | assertFalse(thread.isAlive()); 23 | } 24 | } 25 | 26 | --------------------------------------------------------------------------------