├── .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 |
--------------------------------------------------------------------------------