├── .gitignore
├── README.md
├── assets
├── java-concurrency
│ ├── blockingqueue
│ │ └── blockingqueue-1.png
│ ├── compare-and-swap
│ │ ├── compare-and-swap-0.png
│ │ └── compare-and-swap-1.png
│ ├── deadlock-prevention
│ │ └── deadlock-detection.png
│ ├── false-sharing
│ │ └── false-sharing.png
│ ├── forkjoinpool
│ │ ├── fork-join-pool-1.png
│ │ ├── fork-join-pool-2.png
│ │ ├── fork-join-pool-3.png
│ │ └── fork-join-pool-4.png
│ ├── producer-consumer
│ │ ├── producer-consumer-overview.png
│ │ ├── producer-consumer-use-cases-1.png
│ │ └── producer-consumer-use-cases-2.png
│ ├── thread-congestion
│ │ ├── thread-congestion-1.png
│ │ ├── thread-congestion-2.png
│ │ ├── thread-congestion-3.png
│ │ └── thread-congestion-4.png
│ ├── tread-signaling
│ │ ├── thread-signaling-1.png
│ │ └── thread-signaling-2.png
│ └── virtual-threads
│ │ └── virtual-threads-1.png
└── toc.txt
└── src
└── main
└── java
└── com
└── jenkov
└── java
├── collections
└── SetOfExample.java
├── concurrency
├── blockingqueue
│ ├── AdditionalMethods.java
│ ├── BlockingQueueExample.java
│ ├── BlockingQueueUsageExample.java
│ ├── Consumer.java
│ ├── DequeueMethods.java
│ ├── DrainMethods.java
│ ├── EnqueueMethods.java
│ ├── PeekMethods.java
│ ├── Producer.java
│ └── ProducerConsumerExample.java
├── compareandswap
│ ├── CompareAndSwapExample.java
│ ├── CompareAndSwapLock.java
│ ├── CountRunnable.java
│ ├── Counter.java
│ ├── MyLock.java
│ ├── OptimisticLockCounter.java
│ ├── ProblematicLock.java
│ └── SimpleCounter.java
├── deadlock
│ ├── DeadlockExample.java
│ ├── Runnable1.java
│ ├── Runnable2.java
│ ├── RunnableSync1.java
│ ├── RunnableSync2.java
│ ├── detection
│ │ ├── DeadlockDetection.java
│ │ ├── DeadlockDetectionExample.java
│ │ ├── LockGraphFacade.java
│ │ ├── LockGraphFacadeExample.java
│ │ ├── LockNode.java
│ │ ├── Runnable1DeadlockDetection.java
│ │ ├── Runnable2DeadlockDetection.java
│ │ └── ThreadNode.java
│ └── prevention
│ │ ├── DeadlockTimeoutExample.java
│ │ ├── Runnable1TimeOut.java
│ │ └── Runnable2TimeOut.java
├── falsesharing
│ ├── Counter1.java
│ ├── Counter2.java
│ ├── Counter3.java
│ ├── Counter4.java
│ └── FalseSharingExample.java
├── forkjoinpool
│ ├── JavaForkJoinPool2Example.java
│ ├── JavaForkJoinPoolExample.java
│ ├── MyRecursiveAction.java
│ └── MyRecursiveTask.java
├── samethreading
│ ├── BackgroundRunnable.java
│ ├── ForegroundRunnable.java
│ ├── IAgent.java
│ ├── Main.java
│ ├── PrintAgent.java
│ ├── SubAgent.java
│ ├── SystemThreadRunnable.java
│ └── ThreadSystem.java
├── threadcongestion
│ ├── ConsumerRunnable.java
│ ├── ThreadCongestionExample.java
│ ├── ThreadCongestionExample2.java
│ └── ThreadPipelineMain.java
├── threadpipeline
│ ├── Processor.java
│ ├── Step1Processor.java
│ ├── Step2Processor.java
│ └── ThreadPipeline.java
├── threadsignaling
│ ├── SignalCarrier.java
│ ├── SignalCounter.java
│ ├── SignalHolder.java
│ ├── SpuriousWakeupSignalGuard.java
│ ├── ThreadSignalingExample.java
│ ├── ThreadSignalingExample2.java
│ ├── ThreadSignalingExample3.java
│ ├── ThreadSignalingExample4.java
│ └── ThreadSignalingExampleBasic.java
└── virtualthreads
│ ├── ExecutorServiceVirtualThreadsExample.java
│ ├── VirtualThreadExample.java
│ └── VirtualThreadExample2.java
├── generics
├── Car.java
├── JavaGenericsExample1.java
├── JavaGenericsExample2.java
├── Truck.java
└── Vehicle.java
└── switchexp
└── SwitchExamples.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.iml
3 |
4 | target/
5 | out/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Java Examples
2 | A set of Java examples - of Java SE features (core Java) and techniques.
3 |
4 | The Java examples are related to the Java tutorials at jenkov.com .
5 | Many of these Java examples will be hard to understand without the corresponding tutorial explaining the topic and
6 | the examples.
7 |
8 | # Examples Use Latest Version of Java
9 | Since part of the examples in this Git repository are using new Java language features - you should use the
10 | latest version of Java when trying to run them.
11 |
12 | ## Java Language Examples
13 | - [Java Generics Example](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/virtualthreads/VirtualThreadExample.java)
14 |
15 | ## Java Concurrency Examples
16 |
17 | - [Java Virtual Thread Example](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/virtualthreads/VirtualThreadExample.java)
18 | - [Java Deadlock](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/deadlock/DeadlockExample.java)
19 | - [Java Deadlock Prevention - Timeout Backoff](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/deadlock/prevention/DeadlockTimeoutExample.java)
20 | - [Java False Sharing Example](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/falsesharing/FalseSharingExample.java)
21 | - [Java Thread Congestion - Shared BlockingQueue Example](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadcongestion/ThreadCongestionExample.java)
22 | - [Java Thread Congestion - Separate BlockingQueue Example](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadcongestion/ThreadCongestionExample2.java)
23 | - [Java Thread Signaling Example 1](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample.java)
24 | - [Java Thread Signaling Example 2](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample2.java)
25 | - [Java Thread Signaling Example 3](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample3.java)
26 | - [Java Thread Signaling Example 4](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample4.java)
27 | - [Java ForkJoinPool Example 1](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/forkjoinpool/JavaForkJoinPoolExample.java)
28 | - [Java ForkJoinPool Example 2](https://github.com/jjenkov/java-examples/blob/main/src/main/java/com/jenkov/java/concurrency/forkjoinpool/JavaForkJoinPoolExample2.java)
29 |
30 |
31 |
--------------------------------------------------------------------------------
/assets/java-concurrency/blockingqueue/blockingqueue-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/blockingqueue/blockingqueue-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/compare-and-swap/compare-and-swap-0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/compare-and-swap/compare-and-swap-0.png
--------------------------------------------------------------------------------
/assets/java-concurrency/compare-and-swap/compare-and-swap-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/compare-and-swap/compare-and-swap-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/deadlock-prevention/deadlock-detection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/deadlock-prevention/deadlock-detection.png
--------------------------------------------------------------------------------
/assets/java-concurrency/false-sharing/false-sharing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/false-sharing/false-sharing.png
--------------------------------------------------------------------------------
/assets/java-concurrency/forkjoinpool/fork-join-pool-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/forkjoinpool/fork-join-pool-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/forkjoinpool/fork-join-pool-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/forkjoinpool/fork-join-pool-2.png
--------------------------------------------------------------------------------
/assets/java-concurrency/forkjoinpool/fork-join-pool-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/forkjoinpool/fork-join-pool-3.png
--------------------------------------------------------------------------------
/assets/java-concurrency/forkjoinpool/fork-join-pool-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/forkjoinpool/fork-join-pool-4.png
--------------------------------------------------------------------------------
/assets/java-concurrency/producer-consumer/producer-consumer-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/producer-consumer/producer-consumer-overview.png
--------------------------------------------------------------------------------
/assets/java-concurrency/producer-consumer/producer-consumer-use-cases-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/producer-consumer/producer-consumer-use-cases-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/producer-consumer/producer-consumer-use-cases-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/producer-consumer/producer-consumer-use-cases-2.png
--------------------------------------------------------------------------------
/assets/java-concurrency/thread-congestion/thread-congestion-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/thread-congestion/thread-congestion-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/thread-congestion/thread-congestion-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/thread-congestion/thread-congestion-2.png
--------------------------------------------------------------------------------
/assets/java-concurrency/thread-congestion/thread-congestion-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/thread-congestion/thread-congestion-3.png
--------------------------------------------------------------------------------
/assets/java-concurrency/thread-congestion/thread-congestion-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/thread-congestion/thread-congestion-4.png
--------------------------------------------------------------------------------
/assets/java-concurrency/tread-signaling/thread-signaling-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/tread-signaling/thread-signaling-1.png
--------------------------------------------------------------------------------
/assets/java-concurrency/tread-signaling/thread-signaling-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/tread-signaling/thread-signaling-2.png
--------------------------------------------------------------------------------
/assets/java-concurrency/virtual-threads/virtual-threads-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjenkov/java-examples/7ea0254a9315461c88fcada3f4c1644bb6d26130/assets/java-concurrency/virtual-threads/virtual-threads-1.png
--------------------------------------------------------------------------------
/assets/toc.txt:
--------------------------------------------------------------------------------
1 |
2 | Deadlock Prevention & Detection
3 |
4 | - Lock Reordering
5 |
6 | - Timeout backoff
7 |
8 | - Deadlock detection
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/collections/SetOfExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.collections;
2 |
3 | import java.util.Set;
4 |
5 | public class SetOfExample {
6 |
7 | public static void main(String[] args) {
8 | Set strings = Set.of("123", "456", "789");
9 |
10 | System.out.println(strings);
11 |
12 | strings.add("123");
13 |
14 | System.out.println(strings);
15 |
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/AdditionalMethods.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | public class AdditionalMethods {
7 |
8 | public static void main(String[] args) {
9 | BlockingQueue blockingQueue =
10 | new ArrayBlockingQueue<>(3);
11 |
12 | int size = blockingQueue.size();
13 |
14 | int capacity = blockingQueue.remainingCapacity();
15 |
16 | boolean containsElement =
17 | blockingQueue.contains("1");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/BlockingQueueExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.LinkedBlockingQueue;
6 |
7 | public class BlockingQueueExample {
8 |
9 | public static void main(String[] args) {
10 |
11 | BlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3);
12 | BlockingQueue linkedBlockingQueue = new LinkedBlockingQueue();
13 |
14 | // java.util.concurrent.DelayQueue
15 | // java.util.concurrent.LinkedBlockingDeque
16 | // java.util.concurrent.LinkedTransferQueue
17 | // java.util.concurrent.PriorityBlockingQueue
18 | // java.util.concurrent.SynchronousQueue
19 |
20 |
21 |
22 |
23 |
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/BlockingQueueUsageExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.LinkedBlockingQueue;
6 |
7 | public class BlockingQueueUsageExample {
8 |
9 | public static void main(String[] args) throws InterruptedException {
10 |
11 | BlockingQueue blockingQueue =
12 | new ArrayBlockingQueue<>(3);
13 |
14 | blockingQueue.put("element 1");
15 | blockingQueue.put("element 2");
16 |
17 | String element1 = blockingQueue.take();
18 | String element2 = blockingQueue.take();
19 |
20 | System.out.println(element1);
21 | System.out.println(element2);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/Consumer.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 |
5 | public class Consumer implements Runnable {
6 | BlockingQueue blockingQueue = null;
7 |
8 | public Consumer(BlockingQueue queue) {
9 | this.blockingQueue = queue;
10 | }
11 |
12 | @Override
13 | public void run() {
14 | while(true){
15 | try {
16 | String element =
17 | this.blockingQueue.take();
18 | String text = Thread.currentThread().getName() +
19 | " consumed " + element;
20 | System.out.println(text);
21 | } catch (InterruptedException e) {
22 | e.printStackTrace();
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/DequeueMethods.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | public class DequeueMethods {
8 |
9 | public static void main(String[] args) {
10 | BlockingQueue blockingQueue =
11 | new ArrayBlockingQueue<>(3);
12 |
13 | // take() blocks until an element becomes available
14 | try {
15 | String element = blockingQueue.take();
16 | } catch (InterruptedException e) {
17 | e.printStackTrace();
18 | }
19 |
20 | // poll() returns null if no element is available
21 | String element2 = blockingQueue.poll();
22 |
23 | // poll(long timeout, TimeUnit timeUnit) blocks up until timeout
24 | // for an element to become available. If no element is available
25 | // before that time, null is returned.
26 | try {
27 | String element3 = blockingQueue.poll(1000, TimeUnit.MILLISECONDS);
28 | } catch (InterruptedException e) {
29 | e.printStackTrace();
30 | }
31 |
32 |
33 | // removes the element if present in the BlockingQueue
34 | boolean wasRemoved = blockingQueue.remove("1");
35 |
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/DrainMethods.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.concurrent.ArrayBlockingQueue;
6 | import java.util.concurrent.BlockingQueue;
7 |
8 | public class DrainMethods {
9 |
10 | public static void main(String[] args) {
11 | BlockingQueue blockingQueue =
12 | new ArrayBlockingQueue<>(10);
13 |
14 | Collection dest = new ArrayList();
15 |
16 | blockingQueue.drainTo(dest);
17 |
18 | blockingQueue.drainTo(dest, 5);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/EnqueueMethods.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | public class EnqueueMethods {
8 |
9 | public static void main(String[] args) {
10 | BlockingQueue blockingQueue =
11 | new ArrayBlockingQueue<>(3);
12 |
13 | // put() will block until there is space
14 | // inside the BlockingQueue for the element
15 | try {
16 | blockingQueue.put("1");
17 | } catch (InterruptedException e) {
18 | e.printStackTrace();
19 | }
20 |
21 | // add will throw IllegalStateException if
22 | // no space available in BlockingQueue
23 | try{
24 | blockingQueue.add("2");
25 | } catch(IllegalStateException e) {
26 | // no space inside BlockingQueue
27 | }
28 |
29 | // offer() returns false if no space
30 | boolean wasEnqueued = blockingQueue.offer("3");
31 |
32 | // offer(o, time, TimeUnit) blocks for time if no space,
33 | // then returns false if still no space.
34 | try {
35 | boolean wasEnqueued2 =
36 | blockingQueue.offer("3", 1000, TimeUnit.MILLISECONDS);
37 | } catch (InterruptedException e) {
38 | e.printStackTrace();
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/PeekMethods.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.NoSuchElementException;
4 | import java.util.concurrent.ArrayBlockingQueue;
5 | import java.util.concurrent.BlockingQueue;
6 |
7 | public class PeekMethods {
8 |
9 | public static void main(String[] args) {
10 | BlockingQueue blockingQueue =
11 | new ArrayBlockingQueue<>(3);
12 |
13 | String element1 = blockingQueue.peek();
14 |
15 | try {
16 | String element2 = blockingQueue.element();
17 | } catch(NoSuchElementException e) {
18 | System.out.println("BlockingQueue is empty");
19 | }
20 |
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/Producer.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 |
5 | public class Producer implements Runnable {
6 | BlockingQueue blockingQueue = null;
7 |
8 | public Producer(BlockingQueue queue) {
9 | this.blockingQueue = queue;
10 | }
11 |
12 | @Override
13 | public void run() {
14 | while(true) {
15 | long timeMillis = System.currentTimeMillis();
16 | try {
17 | this.blockingQueue.put("" + timeMillis);
18 | } catch (InterruptedException e) {
19 | System.out.println("Producer was interrupted");
20 | }
21 | sleep(1000);
22 | }
23 | }
24 |
25 | private void sleep(long timeMillis) {
26 | try {
27 | Thread.sleep(timeMillis);
28 | } catch (InterruptedException e) {
29 | e.printStackTrace();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/blockingqueue/ProducerConsumerExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.blockingqueue;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | public class ProducerConsumerExample {
7 |
8 | public static void main(String[] args) {
9 | BlockingQueue blockingQueue =
10 | new ArrayBlockingQueue<>(3);
11 |
12 | Producer producer = new Producer(blockingQueue);
13 | Consumer consumer1 = new Consumer(blockingQueue);
14 | Consumer consumer2 = new Consumer(blockingQueue);
15 |
16 | Thread producerThread = new Thread(producer);
17 | Thread consumerThread1 = new Thread(consumer1);
18 | Thread consumerThread2 = new Thread(consumer2);
19 | producerThread.start();
20 | consumerThread1.start();
21 | consumerThread2.start();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/compareandswap/CompareAndSwapExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.compareandswap;
2 |
3 | public class CompareAndSwapExample {
4 |
5 | public static void main(String[] args) {
6 |
7 | Counter counter = new SimpleCounter(new ProblematicLock());
8 | //Counter counter = new SimpleCounter(new CompareAndSwapLock());
9 | //Counter counter = new OptimisticLockCounter();
10 |
11 | CountRunnable runnable1 = new CountRunnable(counter, 1_000_000);
12 | CountRunnable runnable2 = new CountRunnable(counter, 1_000_000);
13 |
14 | Thread thread1 = new Thread(runnable1);
15 | Thread thread2 = new Thread(runnable2);
16 |
17 | thread1.start();
18 | thread2.start();
19 |
20 |
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/compareandswap/CompareAndSwapLock.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.compareandswap;
2 |
3 | import java.util.concurrent.atomic.AtomicBoolean;
4 |
5 | public class CompareAndSwapLock implements MyLock{
6 |
7 | private AtomicBoolean atomicLocked = new AtomicBoolean(false);
8 |
9 |
10 | public void unlock() {
11 | this.atomicLocked.set(false);
12 | }
13 |
14 | public void lock() {
15 | while(!this.atomicLocked.compareAndSet(false, true)) {
16 | // busy wait - until compareAndSet() succeeds
17 | }
18 |
19 |
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/compareandswap/CountRunnable.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.compareandswap;
2 |
3 | public class CountRunnable implements Runnable {
4 |
5 | private Counter counter = null;
6 | private long iterations = 0;
7 |
8 | public CountRunnable(Counter counter, long iterations) {
9 | this.counter = counter;
10 | this.iterations = iterations;
11 | }
12 |
13 | @Override
14 | public void run() {
15 | for(int i=0; i involvedThreadNodes = new HashSet<>();
10 |
11 | while(true) {
12 | ThreadNode lockedByThread = lockNode.lockedBy;
13 |
14 | if(involvedThreadNodes.contains(lockedByThread)) {
15 | return true;
16 | }
17 | involvedThreadNodes.add(lockedByThread);
18 |
19 | if(lockedByThread.waitingFor == null) {
20 | return false;
21 | }
22 | lockNode = lockedByThread.waitingFor;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/DeadlockDetectionExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | public class DeadlockDetectionExample {
4 |
5 | public static void main(String[] args) {
6 |
7 | LockNode lockNode1 = new LockNode();
8 | ThreadNode threadNode1 = new ThreadNode();
9 | lockNode1.lockedBy = threadNode1;
10 |
11 | LockNode lockNode2 = new LockNode();
12 | ThreadNode threadNode2 = new ThreadNode();
13 | lockNode2.lockedBy = threadNode2;
14 |
15 | LockNode lockNode3 = new LockNode();
16 | ThreadNode threadNode3 = new ThreadNode();
17 | lockNode3.lockedBy = threadNode3;
18 |
19 | threadNode1.waitingFor = lockNode2;
20 | //threadNode2.waitingFor = lockNode3;
21 | threadNode3.waitingFor = lockNode1;
22 |
23 |
24 | DeadlockDetection deadlockDetection = new DeadlockDetection();
25 |
26 | boolean involvedInDeadlock1 = deadlockDetection.isInvolvedInDeadlock(lockNode1);
27 | boolean involvedInDeadlock2 = deadlockDetection.isInvolvedInDeadlock(lockNode2);
28 | boolean involvedInDeadlock3 = deadlockDetection.isInvolvedInDeadlock(lockNode3);
29 |
30 | System.out.println(involvedInDeadlock1);
31 | System.out.println(involvedInDeadlock2);
32 | System.out.println(involvedInDeadlock3);
33 |
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/LockGraphFacade.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.concurrent.locks.Lock;
6 |
7 | public class LockGraphFacade {
8 |
9 | private DeadlockDetection deadlockDetection = new DeadlockDetection();
10 |
11 | private Map threadNodes = new HashMap<>();
12 | private Map lockNodes = new HashMap<>();
13 |
14 | public synchronized boolean tryLock(Lock lock) {
15 | Thread currentThread = Thread.currentThread();
16 | return tryLock(lock, currentThread);
17 | }
18 |
19 | public synchronized boolean tryLock(Lock lock, Thread currentThread) {
20 | System.out.println(currentThread.getName() + " tryLock()...");
21 | LockNode lockNode = getOrCreateLockNode(lock);
22 |
23 | ThreadNode threadNode = getOrCreateThreadNode(currentThread);
24 |
25 | if(lockNode.lockedBy == threadNode) {
26 | return true;
27 | }
28 | if(lockNode.lockedBy == null) {
29 | lockNode.lockedBy = threadNode;
30 | lock.lock();
31 | return true;
32 | }
33 |
34 | threadNode.waitingFor = lockNode;
35 |
36 | if(this.deadlockDetection.isInvolvedInDeadlock(lockNode)){
37 | threadNode.waitingFor = null;
38 | return false;
39 | }
40 |
41 | // Lock is locked by another thread, but is not part of a deadlock,
42 | // so it is safe to wait to lock the Lock at a later time.
43 | lock.lock();
44 | threadNode.waitingFor = null;
45 | lockNode.lockedBy = threadNode;
46 | return true;
47 | }
48 |
49 | public synchronized void unlock(Lock lock) {
50 | lock.unlock();
51 | LockNode lockNode = getOrCreateLockNode(lock);
52 | lockNode.lockedBy = null;
53 | }
54 |
55 | private LockNode getOrCreateLockNode(Lock lock) {
56 | LockNode lockNode = this.lockNodes.get(lock);
57 | if(lockNode == null) {
58 | lockNode = new LockNode();
59 | this.lockNodes.put(lock, lockNode);
60 | }
61 | return lockNode;
62 | }
63 |
64 | private ThreadNode getOrCreateThreadNode(Thread thread) {
65 | ThreadNode threadNode = this.threadNodes.get(thread);
66 | if(threadNode == null) {
67 | threadNode = new ThreadNode();
68 | threadNode.thread = thread;
69 | this.threadNodes.put(thread, threadNode);
70 | }
71 | return threadNode;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/LockGraphFacadeExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | import java.util.concurrent.locks.Lock;
4 | import java.util.concurrent.locks.ReentrantLock;
5 |
6 | public class LockGraphFacadeExample {
7 |
8 | public static void main(String[] args) {
9 | withThreads();
10 | }
11 |
12 | private static void withThreads() {
13 | LockGraphFacade lockGraphFacade = new LockGraphFacade();
14 |
15 | Lock lock1 = new ReentrantLock();
16 | Lock lock2 = new ReentrantLock();
17 |
18 | Runnable1DeadlockDetection runnable1 =
19 | new Runnable1DeadlockDetection(lockGraphFacade, lock1, lock2);
20 | Runnable2DeadlockDetection runnable2 =
21 | new Runnable2DeadlockDetection(lockGraphFacade, lock1, lock2);
22 |
23 | Thread thread1 = new Thread(runnable1);
24 | Thread thread2 = new Thread(runnable2);
25 | thread1.start();
26 | thread2.start();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/LockNode.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | public class LockNode {
4 |
5 | public ThreadNode lockedBy = null;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/Runnable1DeadlockDetection.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | import java.util.concurrent.TimeUnit;
4 | import java.util.concurrent.locks.Lock;
5 |
6 | public class Runnable1DeadlockDetection implements Runnable{
7 |
8 | private LockGraphFacade lockGraphFacade = null;
9 | private Lock lock1 = null;
10 | private Lock lock2 = null;
11 |
12 | public Runnable1DeadlockDetection(LockGraphFacade lockGraphFacade, Lock lock1, Lock lock2) {
13 | this.lockGraphFacade = lockGraphFacade;
14 | this.lock1 = lock1;
15 | this.lock2 = lock2;
16 | }
17 |
18 | @Override
19 | public void run() {
20 | String threadName = Thread.currentThread().getName();
21 |
22 | while(true) {
23 | int failureCount = 0;
24 | while(! tryLockBothLocks()) {
25 | failureCount++;
26 | System.err.println(threadName + " failed to lock both Locks. " +
27 | "Waiting a bit before retrying [" + failureCount + " tries]");
28 | sleep(100L * ((long) Math.random()));
29 | }
30 | if(failureCount > 0) {
31 | System.out.println(threadName +
32 | " succeeded in locking both locks - after " + failureCount + " failures.");
33 | }
34 |
35 | //do the work - now that both locks have been acquired (locked by this thread)
36 |
37 | //unlock
38 | this.lockGraphFacade.unlock(this.lock2);
39 | this.lockGraphFacade.unlock(this.lock1);
40 | }
41 | }
42 |
43 |
44 |
45 | private boolean tryLockBothLocks() {
46 | String threadName = Thread.currentThread().getName();
47 |
48 | System.out.println(threadName + " lock1: attempt lock");
49 | boolean lock1Succeeded = this.lockGraphFacade.tryLock(this.lock1);
50 | if(!lock1Succeeded) {
51 | return false;
52 | }
53 | System.out.println(threadName + " lock1: locked");
54 |
55 | sleep(1000);
56 |
57 | System.out.println(threadName + " lock2: attempt lock");
58 | boolean lock2Succeeded = this.lockGraphFacade.tryLock(this.lock2);
59 | if(!lock2Succeeded) {
60 | this.lockGraphFacade.unlock(lock1);
61 | return false;
62 | }
63 | System.out.println(threadName + " lock2: locked");
64 |
65 | return true;
66 | }
67 |
68 | private void sleep(long timeMillis) {
69 | try {
70 | Thread.sleep(timeMillis);
71 | } catch (InterruptedException e) {
72 | e.printStackTrace();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/Runnable2DeadlockDetection.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | import java.util.concurrent.locks.Lock;
4 |
5 | public class Runnable2DeadlockDetection implements Runnable{
6 |
7 | private LockGraphFacade lockGraphFacade = null;
8 | private Lock lock1 = null;
9 | private Lock lock2 = null;
10 |
11 | public Runnable2DeadlockDetection(LockGraphFacade lockGraphFacade, Lock lock1, Lock lock2) {
12 | this.lockGraphFacade = lockGraphFacade;
13 | this.lock1 = lock1;
14 | this.lock2 = lock2;
15 | }
16 |
17 | @Override
18 | public void run() {
19 | String threadName = Thread.currentThread().getName();
20 |
21 | while(true) {
22 | int failureCount = 0;
23 | while(! tryLockBothLocks()) {
24 | failureCount++;
25 | System.err.println(threadName + " failed to lock both Locks. " +
26 | "Waiting a bit before retrying [" + failureCount + " tries]");
27 | sleep(100L * ((long) Math.random()));
28 | }
29 | if(failureCount > 0) {
30 | System.out.println(threadName +
31 | " succeeded in locking both locks - after " + failureCount + " failures.");
32 | }
33 |
34 | //do the work - now that both locks have been acquired (locked by this thread)
35 |
36 | //unlock
37 | this.lockGraphFacade.unlock(this.lock2);
38 | this.lockGraphFacade.unlock(this.lock1);
39 | }
40 | }
41 |
42 | private void sleep(long timeMillis) {
43 | try {
44 | Thread.sleep(timeMillis);
45 | } catch (InterruptedException e) {
46 | e.printStackTrace();
47 | }
48 | }
49 |
50 | private boolean tryLockBothLocks() {
51 | String threadName = Thread.currentThread().getName();
52 |
53 | System.out.println(threadName + " lock2: attempt lock");
54 | boolean lock2Succeeded = this.lockGraphFacade.tryLock(this.lock2);
55 | if(!lock2Succeeded) {
56 | return false;
57 | }
58 | System.out.println(threadName + " lock2: locked");
59 |
60 | sleep(1000);
61 |
62 | System.out.println(threadName + " lock1: attempt lock");
63 | boolean lock1Succeeded = this.lockGraphFacade.tryLock(this.lock1);
64 | if(!lock1Succeeded) {
65 | this.lockGraphFacade.unlock(lock2);
66 | return false;
67 | }
68 | System.out.println(threadName + " lock1: locked");
69 |
70 | return true;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/detection/ThreadNode.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.detection;
2 |
3 | public class ThreadNode {
4 |
5 | public LockNode waitingFor = null;
6 | public Thread thread = null;
7 |
8 |
9 |
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/prevention/DeadlockTimeoutExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.prevention;
2 |
3 | import java.util.concurrent.locks.Lock;
4 | import java.util.concurrent.locks.ReentrantLock;
5 |
6 | public class DeadlockTimeoutExample {
7 |
8 | public static void main(String[] args) {
9 |
10 | Lock lock1 = new ReentrantLock();
11 | Lock lock2 = new ReentrantLock();
12 |
13 | Runnable runnable1 = new Runnable1TimeOut(lock1, lock2);
14 | Runnable runnable2 = new Runnable2TimeOut(lock1, lock2);
15 |
16 | Thread thread1 = new Thread(runnable1);
17 | Thread thread2 = new Thread(runnable2);
18 |
19 | thread1.start();
20 | thread2.start();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/prevention/Runnable1TimeOut.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.prevention;
2 |
3 | import java.util.concurrent.TimeUnit;
4 | import java.util.concurrent.locks.Lock;
5 |
6 | public class Runnable1TimeOut implements Runnable{
7 |
8 | private Lock lock1 = null;
9 | private Lock lock2 = null;
10 |
11 | public Runnable1TimeOut(Lock lock1, Lock lock2) {
12 | this.lock1 = lock1;
13 | this.lock2 = lock2;
14 | }
15 |
16 | @Override
17 | public void run() {
18 | String threadName = Thread.currentThread().getName();
19 |
20 | while(true) {
21 | int failureCount = 0;
22 | while(! tryLockBothLocks()) {
23 | failureCount++;
24 | System.err.println(threadName + " failed to lock both Locks. " +
25 | "Waiting a bit before retrying [" + failureCount + " tries]");
26 | sleep(100L * ((long) Math.random()));
27 | }
28 | if(failureCount > 0) {
29 | System.out.println(threadName +
30 | " succeeded in locking both locks - after " + failureCount + " failures.");
31 | }
32 |
33 | //do the work - now that both locks have been acquired (locked by this thread)
34 |
35 | //unlock
36 | lock2.unlock();
37 | lock1.unlock();
38 | }
39 | }
40 |
41 | private void sleep(long timeMillis) {
42 | try {
43 | Thread.sleep(timeMillis);
44 | } catch (InterruptedException e) {
45 | e.printStackTrace();
46 | }
47 | }
48 |
49 | private boolean tryLockBothLocks() {
50 | String threadName = Thread.currentThread().getName();
51 |
52 | try {
53 | boolean lock1Succeeded = lock1.tryLock(1000, TimeUnit.MILLISECONDS);
54 | if(!lock1Succeeded) {
55 | return false;
56 | }
57 | } catch (InterruptedException e) {
58 | System.out.println(threadName + " interrupted trying to lock Lock 1");
59 | return false;
60 | }
61 | try {
62 | boolean lock2Succeeded = lock2.tryLock(1000, TimeUnit.MILLISECONDS);
63 | if(!lock2Succeeded) {
64 | lock1.unlock();
65 | return false;
66 | }
67 | } catch (InterruptedException e) {
68 | System.out.println(threadName + " interrupted trying to lock Lock 2");
69 | lock1.unlock();
70 | return false;
71 | }
72 |
73 | return true;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/deadlock/prevention/Runnable2TimeOut.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.deadlock.prevention;
2 |
3 | import java.util.concurrent.TimeUnit;
4 | import java.util.concurrent.locks.Lock;
5 |
6 | public class Runnable2TimeOut implements Runnable{
7 |
8 | private Lock lock1 = null;
9 | private Lock lock2 = null;
10 |
11 | public Runnable2TimeOut(Lock lock1, Lock lock2) {
12 | this.lock1 = lock1;
13 | this.lock2 = lock2;
14 | }
15 |
16 | @Override
17 | public void run() {
18 | String threadName = Thread.currentThread().getName();
19 |
20 | while(true) {
21 | int failureCount = 0;
22 | while(! tryLockBothLocks()) {
23 | failureCount++;
24 | System.err.println(threadName + " failed to lock both Locks. Waiting a bit before retrying [" + failureCount + " tries]");
25 | sleep(100L * ((long) Math.random()));
26 | }
27 | if(failureCount > 0) {
28 | System.out.println(threadName + " succeeded in locking both locks - after " + failureCount + " failures.");
29 | }
30 |
31 | //do the work - now that both locks have been acquired (locked by this thread)
32 |
33 | //unlock
34 | lock2.unlock();
35 | lock1.unlock();
36 | }
37 | }
38 |
39 | private void sleep(long timeMillis) {
40 | try {
41 | Thread.sleep(timeMillis);
42 | } catch (InterruptedException e) {
43 | e.printStackTrace();
44 | }
45 | }
46 |
47 | private boolean tryLockBothLocks() {
48 | String threadName = Thread.currentThread().getName();
49 |
50 | try {
51 | boolean lock2Succeeded = lock2.tryLock(1000, TimeUnit.MILLISECONDS);
52 | if(!lock2Succeeded) {
53 | return false;
54 | }
55 | } catch (InterruptedException e) {
56 | System.out.println(threadName + " interrupted trying to lock Lock 2");
57 | return false;
58 | }
59 | try {
60 | boolean lock1Succeeded = lock1.tryLock(1000, TimeUnit.MILLISECONDS);
61 | if(!lock1Succeeded) {
62 | lock2.unlock();
63 | return false;
64 | }
65 | } catch (InterruptedException e) {
66 | System.out.println(threadName + " interrupted trying to lock Lock 1");
67 | lock1.unlock();
68 | return false;
69 | }
70 |
71 | return true;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/falsesharing/Counter1.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.falsesharing;
2 |
3 |
4 | public class Counter1 {
5 |
6 | public volatile long count1 = 0;
7 |
8 | public volatile long count2 = 0;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/falsesharing/Counter2.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.falsesharing;
2 |
3 |
4 | public class Counter2 {
5 |
6 | @jdk.internal.vm.annotation.Contended
7 | public volatile long count1 = 0;
8 | //padding bytes
9 | public volatile long count2 = 0;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/falsesharing/Counter3.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.falsesharing;
2 |
3 |
4 | @jdk.internal.vm.annotation.Contended
5 | public class Counter3 {
6 |
7 | public volatile long count1 = 0;
8 | //padding bytes
9 |
10 | public volatile long count2 = 0;
11 | //padding bytes
12 |
13 | public volatile long count3 = 0;
14 | //padding bytes
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/falsesharing/Counter4.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.falsesharing;
2 |
3 |
4 | public class Counter4 {
5 |
6 | @jdk.internal.vm.annotation.Contended("group1")
7 | public volatile long count1 = 0;
8 |
9 | @jdk.internal.vm.annotation.Contended("group1")
10 | public volatile long count2 = 0;
11 |
12 | @jdk.internal.vm.annotation.Contended("group2")
13 | public volatile long count3 = 0;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/falsesharing/FalseSharingExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.falsesharing;
2 |
3 | public class FalseSharingExample {
4 |
5 | public static void main(String[] args) {
6 |
7 | Counter3 counter1 = new Counter3();
8 | Counter3 counter2 = counter1;
9 | //Counter2 counter2 = new Counter1();
10 |
11 |
12 | long iterations = 1_000_000_000;
13 |
14 | Thread thread1 = new Thread(() -> {
15 | long startTime = System.currentTimeMillis();
16 | for(long i=0; i {
23 | long startTime = System.currentTimeMillis();
24 | for(long i=0; i forkJoinTask = forkJoinPool1.submit(myRecursiveTask);
20 | try {
21 | Long result = forkJoinTask.get();
22 | } catch (InterruptedException e) {
23 | throw new RuntimeException(e);
24 | } catch (ExecutionException e) {
25 | throw new RuntimeException(e);
26 | }
27 |
28 | forkJoinPool1.getParallelism();
29 | forkJoinPool1.setParallelism(10);
30 | forkJoinPool1.getPoolSize();
31 | forkJoinPool1.getQueuedSubmissionCount();
32 | forkJoinPool1.getRunningThreadCount();
33 | forkJoinPool1.isShutdown();
34 | forkJoinPool1.isTerminated();
35 | forkJoinPool1.isTerminating();
36 |
37 | forkJoinPool1.shutdown();
38 | forkJoinPool1.shutdownNow();
39 |
40 |
41 | //System.out.println("Result: "+ result);
42 | sleep(1000); // Make sure all System.out.print() reaches console before app stops.
43 | }
44 |
45 | private static void sleep(long millis) {
46 | try {
47 | Thread.sleep(millis);
48 | } catch (InterruptedException e) {
49 | throw new RuntimeException(e);
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/forkjoinpool/JavaForkJoinPoolExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.forkjoinpool;
2 |
3 | import java.util.concurrent.ForkJoinPool;
4 |
5 | public class JavaForkJoinPoolExample {
6 |
7 | public static void main(String[] args) {
8 | ForkJoinPool forkJoinPool1 = ForkJoinPool.commonPool();
9 | ForkJoinPool forkJoinPool2 = new ForkJoinPool(4);
10 |
11 | MyRecursiveAction myRecursiveAction = new MyRecursiveAction(123);
12 | forkJoinPool1.invoke(myRecursiveAction);
13 |
14 | MyRecursiveTask myRecursiveTask = new MyRecursiveTask(123);
15 | //long result = forkJoinPool1.invoke(myRecursiveTask);
16 |
17 | //System.out.println("Result: "+ result);
18 | sleep(1000); // Make sure all System.out.print() reaches console before app stops.
19 | }
20 |
21 | private static void sleep(long millis) {
22 | try {
23 | Thread.sleep(millis);
24 | } catch (InterruptedException e) {
25 | throw new RuntimeException(e);
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/forkjoinpool/MyRecursiveAction.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.forkjoinpool;
2 |
3 | import java.util.concurrent.RecursiveAction;
4 |
5 | public class MyRecursiveAction extends RecursiveAction {
6 |
7 | private long workLoad = 0;
8 |
9 | public MyRecursiveAction(long workLoad) {
10 | this.workLoad = workLoad;
11 | }
12 |
13 | @Override
14 | protected void compute() {
15 | //if work is above threshold, break tasks up into smaller tasks
16 | if(this.workLoad > 16) {
17 | System.out.println("Splitting workLoad : " + this.workLoad);
18 |
19 | long workload1 = this.workLoad / 2;
20 | long workload2 = this.workLoad - workload1;
21 |
22 | MyRecursiveAction subtask1 = new MyRecursiveAction(workload1);
23 | MyRecursiveAction subtask2 = new MyRecursiveAction(workload2);
24 |
25 | subtask1.fork();
26 | subtask2.fork();
27 |
28 | } else {
29 | System.out.println("Doing workLoad myself: " + this.workLoad);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/forkjoinpool/MyRecursiveTask.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.forkjoinpool;
2 |
3 | import java.util.concurrent.RecursiveTask;
4 |
5 | public class MyRecursiveTask extends RecursiveTask {
6 |
7 | private long workLoad = 0;
8 |
9 | public MyRecursiveTask(long workLoad) {
10 | this.workLoad = workLoad;
11 | }
12 |
13 | protected Long compute() {
14 |
15 | //if work is above threshold, break tasks up into smaller tasks
16 | if(this.workLoad > 16) {
17 | System.out.println("Splitting workLoad : " + this.workLoad);
18 |
19 | long workload1 = this.workLoad / 2;
20 | long workload2 = this.workLoad - workload1;
21 |
22 | MyRecursiveTask subtask1 = new MyRecursiveTask(workload1);
23 | MyRecursiveTask subtask2 = new MyRecursiveTask(workload2);
24 |
25 | subtask1.fork();
26 | subtask2.fork();
27 |
28 | long result = 0;
29 | result += subtask1.join();
30 | result += subtask2.join();
31 | return result;
32 |
33 | } else {
34 | System.out.println("Doing workLoad myself: " + this.workLoad);
35 | return workLoad * 3;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/BackgroundRunnable.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | public class BackgroundRunnable implements Runnable {
4 |
5 | @Override
6 | public void run() {
7 |
8 | }
9 |
10 | public void stop() {
11 |
12 | }
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/ForegroundRunnable.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | public class ForegroundRunnable implements Runnable {
4 |
5 | @Override
6 | public void run() {
7 |
8 | }
9 |
10 | public void stop() {
11 |
12 | }
13 |
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/IAgent.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | public interface IAgent {
4 |
5 |
6 | //todo requestTermination() ??
7 |
8 |
9 | public boolean isTerminated();
10 |
11 | public void continueExec();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/Main.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | public class Main {
4 |
5 | public static void main(String[] args) throws InterruptedException {
6 |
7 | // *) Agents transferring themselves or other agents to a different thread
8 | // - ThreadSystem.transferToForegroundThread(IAgent)
9 | // - ThreadSystem.transferToBackgroundThread(IAgent)
10 |
11 | // *) Sub agents releasing messages / results to a parent agent
12 | // - IAgent.getResultQueue()
13 |
14 | // --------------------------------------------------------------------------
15 |
16 | // *) Agent switcher ... like a one-off task executor switching between tasks
17 | // - switcher.addAgent(IAgent agent)
18 | // - switcher.continue(increments)
19 |
20 | // *) Agent switcher - prioritized - so some agents are allowed to execute a higher number of increments than others.
21 |
22 |
23 |
24 | ThreadSystem threadSystem = new ThreadSystem();
25 |
26 | threadSystem.addForegroundThread().submitAgent(new PrintAgent("PA 0", threadSystem));
27 | threadSystem.addForegroundThread().submitAgent(new PrintAgent("PA 1", threadSystem));
28 |
29 | threadSystem.addBackgroundThread();
30 |
31 | threadSystem.start();
32 |
33 | Thread.sleep(1000);
34 |
35 | threadSystem.requestTermination();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/PrintAgent.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | import java.util.concurrent.atomic.AtomicBoolean;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | public class PrintAgent implements IAgent {
7 |
8 | private String agentName = null;
9 | private AtomicBoolean isTerminated = new AtomicBoolean(false);
10 |
11 | private ThreadSystem threadSystem = null;
12 |
13 | private AtomicInteger agentState = new AtomicInteger(0);
14 |
15 | public PrintAgent() {}
16 | public PrintAgent(String agentName, ThreadSystem threadSystem) {
17 | this.agentName = agentName;
18 | this.threadSystem = threadSystem;
19 | }
20 |
21 | @Override
22 | public boolean isTerminated() {
23 | return this.isTerminated.get();
24 | }
25 |
26 | @Override
27 | public void continueExec() {
28 | String threadPlusAgentName = Thread.currentThread().getName() + " " + this.agentName;
29 |
30 | System.out.println(threadPlusAgentName + " running in foreground thread." );
31 |
32 | SubAgent subAgent = new SubAgent();
33 | try {
34 | this.threadSystem.submitToBackgroundThread(subAgent);
35 | } catch (InterruptedException e) {
36 | e.printStackTrace();
37 | }
38 |
39 | for(int i=0; i<10; i++) {
40 | System.out.println(threadPlusAgentName + " Print " + i);
41 |
42 | sleep(500);
43 | }
44 |
45 | while(subAgent.getMessageQueue().size() > 0) {
46 | try {
47 | String message = (String) subAgent.getMessageQueue().take();
48 | System.out.println(threadPlusAgentName + " from SubAgent: " + message);
49 | } catch (InterruptedException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 |
54 | this.isTerminated.set(true);
55 | }
56 |
57 | private void sleep(int sleepIntervalMillis) {
58 | try {
59 | Thread.sleep(sleepIntervalMillis);
60 | } catch (InterruptedException e) {
61 | e.printStackTrace();
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/SubAgent.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 |
7 | public class SubAgent implements IAgent {
8 |
9 |
10 | private BlockingQueue messageQueue = new ArrayBlockingQueue(16);
11 |
12 |
13 | private int increments = 5;
14 |
15 | private AtomicBoolean isTerminated = new AtomicBoolean(false);
16 |
17 |
18 |
19 | @Override
20 | public boolean isTerminated() {
21 | return this.isTerminated.get();
22 | }
23 |
24 | @Override
25 | public void continueExec() {
26 | System.out.println("SubAgent running: " + this.increments);
27 |
28 | try {
29 | getMessageQueue().put("" + this.increments);
30 | } catch (InterruptedException e) {
31 | e.printStackTrace();
32 | }
33 |
34 | this.increments--;
35 | this.isTerminated.set(this.increments <= 0);
36 | }
37 |
38 | public BlockingQueue getMessageQueue() {
39 | return this.messageQueue;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/SystemThreadRunnable.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 |
4 | import java.util.concurrent.ArrayBlockingQueue;
5 | import java.util.concurrent.BlockingQueue;
6 | import java.util.concurrent.TimeUnit;
7 | import java.util.concurrent.atomic.AtomicBoolean;
8 |
9 | /**
10 | * A SystemThreadRunnable should be executing an IAgent instance repeatedly until one of the following conditions are true:
11 | *
12 | *
13 | * 1) The agent has terminated.
14 | *
15 | * 2) The SystemThreadRunnable has been signaled to terminate
16 | *
17 | *
18 | * If the agent being executed has terminated, the SystemThreadRunnable can pull a new IAgent instance from its
19 | * inbound queue of IAgents, and continue executing that IAgent instance.
20 | *
21 | */
22 | public class SystemThreadRunnable implements Runnable {
23 |
24 |
25 | private BlockingQueue agentQueue = new ArrayBlockingQueue(1024);
26 | private AtomicBoolean shouldTerminate = new AtomicBoolean(false);
27 |
28 | public SystemThreadRunnable submitAgent(IAgent agent) throws InterruptedException {
29 | this.agentQueue.put(agent);
30 | return this;
31 | }
32 |
33 | public void requestTermination() {
34 | this.shouldTerminate.set(true);
35 | }
36 |
37 | @Override
38 | public void run() {
39 | while(!shouldTerminate.get()){
40 |
41 | try {
42 | IAgent nextAgent = this.agentQueue.poll(1000, TimeUnit.MILLISECONDS);
43 |
44 | if(nextAgent != null) {
45 | while(!nextAgent.isTerminated()) {
46 | nextAgent.continueExec();
47 | }
48 | }
49 |
50 | } catch (InterruptedException e) {
51 | // ignore
52 | //e.printStackTrace();
53 | }
54 | }
55 | System.out.println(Thread.currentThread().getName() + " Terminated");
56 | }
57 |
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/samethreading/ThreadSystem.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.samethreading;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class ThreadSystem {
7 |
8 | protected List foregroundThreads = new ArrayList<>();
9 | protected List backgroundThreads = new ArrayList<>();
10 |
11 | protected int nextForegroundThreadToMoveTo = 0;
12 | protected int nextBackgroundThreadToMoveTo = 0;
13 |
14 |
15 | public SystemThreadRunnable addForegroundThread() {
16 | SystemThreadRunnable foregroundThread = new SystemThreadRunnable();
17 | this.foregroundThreads.add(foregroundThread);
18 | return foregroundThread;
19 | }
20 |
21 | public SystemThreadRunnable addBackgroundThread() {
22 | SystemThreadRunnable backgroundThread = new SystemThreadRunnable();
23 | this.backgroundThreads.add(backgroundThread);
24 | return backgroundThread;
25 | }
26 |
27 | public ThreadSystem start() {
28 |
29 | for(SystemThreadRunnable foregroundThread : this.foregroundThreads) {
30 | Thread thread = new Thread(foregroundThread);
31 | thread.start();
32 | }
33 |
34 | for(SystemThreadRunnable backgroundThread : this.backgroundThreads) {
35 | Thread thread = new Thread(backgroundThread);
36 | thread.start();
37 | }
38 |
39 | return this;
40 | }
41 |
42 | public ThreadSystem requestTermination() {
43 |
44 | for(SystemThreadRunnable foregroundThread : this.foregroundThreads) {
45 | foregroundThread.requestTermination();
46 | }
47 |
48 | for(SystemThreadRunnable backgroundThread : this.backgroundThreads) {
49 | backgroundThread.requestTermination();
50 | }
51 |
52 | return this;
53 | }
54 |
55 | public void submitToBackgroundThread(IAgent agent) throws InterruptedException {
56 | SystemThreadRunnable backgroundThread = this.backgroundThreads.get(this.nextBackgroundThreadToMoveTo);
57 | backgroundThread.submitAgent(agent);
58 |
59 | this.nextBackgroundThreadToMoveTo++;
60 | this.nextBackgroundThreadToMoveTo = this.nextBackgroundThreadToMoveTo % this.backgroundThreads.size();
61 | }
62 |
63 | public void submitToForegroundThread(IAgent agent) throws InterruptedException {
64 | SystemThreadRunnable foregroundThread = this.foregroundThreads.get(this.nextForegroundThreadToMoveTo);
65 | foregroundThread.submitAgent(agent);
66 |
67 | this.nextForegroundThreadToMoveTo++;
68 | this.nextForegroundThreadToMoveTo = this.nextForegroundThreadToMoveTo % this.foregroundThreads.size();
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadcongestion/ConsumerRunnable.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadcongestion;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 | import java.util.concurrent.TimeUnit;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 |
7 | public class ConsumerRunnable implements Runnable {
8 |
9 | private BlockingQueue blockingQueue = null;
10 |
11 | private AtomicBoolean keepRunning = new AtomicBoolean(true);
12 |
13 | public ConsumerRunnable(BlockingQueue blockingQueue) {
14 | this.blockingQueue = blockingQueue;
15 | }
16 |
17 | public void stop() {
18 | System.out.println("Stopped thread");
19 | this.keepRunning.set(false);
20 | }
21 |
22 | @Override
23 | public void run() {
24 |
25 | System.out.println(Thread.currentThread().getName() + " consumer started.");
26 |
27 | long objectsConsumed = 0;
28 | while (this.keepRunning.get()) {
29 | String obj = takeObjectFromQueue();
30 | if(obj != null) { objectsConsumed++; }
31 | }
32 | System.out.println(Thread.currentThread().getName() + " finishing up");
33 | while (this.blockingQueue.size() > 0) {
34 | String obj = takeObjectFromQueue();
35 | if(obj != null) { objectsConsumed++; }
36 | }
37 | System.out.println(Thread.currentThread().getName() +
38 | " consumer finished: " + objectsConsumed);
39 | }
40 |
41 | private String takeObjectFromQueue() {
42 | try {
43 | return blockingQueue.poll(1000, TimeUnit.MILLISECONDS);
44 | } catch (InterruptedException e) {
45 | e.printStackTrace();
46 | return null;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadcongestion/ThreadCongestionExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadcongestion;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | public class ThreadCongestionExample {
7 |
8 | public static void main(String[] args) {
9 | int objectsToProduce = 1_000_000;
10 |
11 | BlockingQueue blockingQueue =
12 | new ArrayBlockingQueue(objectsToProduce);
13 |
14 | ConsumerRunnable[] consumerRunnables =
15 | new ConsumerRunnable[3];
16 |
17 | synchronized (ThreadCongestionExample.class){
18 | for(int i=0; i {
26 | for(int i=0; i produced " + objectsToProduce);
35 | synchronized (ThreadCongestionExample.class) {
36 | for (int i = 0; i < consumerRunnables.length; i++) {
37 | consumerRunnables[i].stop();
38 | }
39 | }
40 | });
41 | producingThread.start();
42 |
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadcongestion/ThreadCongestionExample2.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadcongestion;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | public class ThreadCongestionExample2 {
7 |
8 | public static void main(String[] args) {
9 | int objectsToProduce = 1_000_000;
10 |
11 | BlockingQueue[] blockingQueues = new BlockingQueue[3];
12 | for(int i=0; i(objectsToProduce);
14 | }
15 |
16 | ConsumerRunnable[] consumerRunnables = new ConsumerRunnable[3];
17 | synchronized (ThreadCongestionExample2.class){
18 | for(int i=0; i {
26 | for(int i=0; i produced " + objectsToProduce);
35 |
36 | synchronized (ThreadCongestionExample2.class) {
37 | for(int i=0; i " + output);
47 | } catch (InterruptedException e) {
48 | if(!this.shutdownRequested) {
49 | System.out.println("Step 1: Failed for input " + input);
50 | e.printStackTrace();
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadpipeline/Step2Processor.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadpipeline;
2 |
3 | import java.util.concurrent.ArrayBlockingQueue;
4 | import java.util.concurrent.BlockingQueue;
5 |
6 | public class Step2Processor implements Processor {
7 |
8 | private BlockingQueue inputQueue = new ArrayBlockingQueue(10);
9 |
10 | private BlockingQueue outputQueue = null;
11 |
12 | private volatile boolean shutdownRequested = false;
13 |
14 | private volatile Thread executingThread = null;
15 |
16 |
17 | @Override
18 | public BlockingQueue setInputQueue(BlockingQueue inputQueue) {
19 | this.inputQueue = inputQueue;
20 | return this.inputQueue;
21 | }
22 |
23 | @Override
24 | public BlockingQueue setOutputQueue(BlockingQueue outputQueue) {
25 | this.outputQueue = outputQueue;
26 | return this.outputQueue;
27 | }
28 |
29 | @Override
30 | public void requestShutdown() {
31 | this.shutdownRequested = true;
32 | this.executingThread.interrupt();
33 | }
34 |
35 | @Override
36 | public void run() {
37 |
38 | this.executingThread = Thread.currentThread();
39 | while(!this.shutdownRequested){
40 | Object input = null;
41 | try {
42 | input = this.inputQueue.take();
43 |
44 | Object output = input.toString().substring(0, 7);
45 |
46 | this.outputQueue.put(output);
47 |
48 | //System.out.println("Step 2: " + input + " => " + output);
49 | } catch (InterruptedException e) {
50 | if(!this.shutdownRequested){
51 | System.out.println("Step 2: Failed for input " + input);
52 | e.printStackTrace();
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadpipeline/ThreadPipeline.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadpipeline;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.ArrayBlockingQueue;
6 | import java.util.concurrent.BlockingQueue;
7 |
8 | public class ThreadPipeline {
9 |
10 | private List processors = new ArrayList<>();
11 |
12 | private BlockingQueue inputQueue = null;
13 | private BlockingQueue outputQueue = null;
14 |
15 | public ThreadPipeline addProcessor(Processor processor){
16 | return this;
17 | }
18 |
19 | public BlockingQueue getInputQueue() {
20 | return this.inputQueue;
21 | }
22 |
23 | public BlockingQueue getOutputQueue() {
24 | return this.outputQueue;
25 | }
26 |
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/SignalCarrier.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class SignalCarrier {
4 |
5 | public void doWait() throws InterruptedException{
6 | synchronized(this) {
7 | System.out.println(Thread.currentThread().getName() + " calling wait()");
8 | this.wait();
9 | System.out.println(Thread.currentThread().getName() + " exited wait()");
10 | }
11 | }
12 |
13 | public void doNotify() {
14 | synchronized (this) {
15 | System.out.println(Thread.currentThread().getName() + " calling notify()");
16 | this.notify();
17 | System.out.println(Thread.currentThread().getName() + " exited notify()");
18 | }
19 | }
20 |
21 | public void doNotifyAll() {
22 | synchronized (this) {
23 | System.out.println(Thread.currentThread().getName() + " calling notify()");
24 | this.notifyAll();
25 | System.out.println(Thread.currentThread().getName() + " exited notify()");
26 | }
27 | }
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/SignalCounter.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class SignalCounter {
4 |
5 | private int signals = 0;
6 |
7 | public void doNotify() {
8 | synchronized (this) {
9 | this.signals++;
10 | System.out.println("Signals stored: " + this.signals);
11 |
12 | this.notify();
13 | }
14 | }
15 |
16 | public void doWait() throws InterruptedException{
17 | synchronized(this) {
18 | this.signals--;
19 | if(this.signals >= 0) {
20 | System.out.println(Thread.currentThread().getName()
21 | + " - " + (this.signals+1) +
22 | " signal(s) were stored. Exiting without wait().");
23 | return;
24 | }
25 | System.out.println(Thread.currentThread().getName() + " calling wait()");
26 | this.wait();
27 | System.out.println(Thread.currentThread().getName() + " exited wait()");
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/SignalHolder.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class SignalHolder {
4 |
5 | private boolean signalRaised = false;
6 | private boolean isThreadWaiting = false;
7 |
8 |
9 | public void doNotify() {
10 | synchronized (this) {
11 | System.out.println(Thread.currentThread().getName() + " calling notify()");
12 | if(!this.isThreadWaiting){
13 | this.signalRaised = true;
14 | }
15 | this.notify();
16 | System.out.println(Thread.currentThread().getName() + " exited notify()");
17 | }
18 | }
19 |
20 | public void doWait() throws InterruptedException{
21 | synchronized(this) {
22 | if(this.signalRaised) {
23 | System.out.println(Thread.currentThread().getName() + " signal was already raised - lowering signal and returning");
24 | this.signalRaised = false;
25 | return;
26 | }
27 | System.out.println(Thread.currentThread().getName() + " calling wait()");
28 | this.isThreadWaiting = true;
29 | this.wait();
30 | this.isThreadWaiting = false;
31 | System.out.println(Thread.currentThread().getName() + " exited wait()");
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/SpuriousWakeupSignalGuard.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class SpuriousWakeupSignalGuard {
4 |
5 | Object myMonitorObject = new Object();
6 | boolean wasSignalled = false;
7 |
8 | public void doNotify(){
9 | synchronized(myMonitorObject){
10 | wasSignalled = true;
11 | myMonitorObject.notify();
12 | }
13 | }
14 |
15 | public void doWait() throws InterruptedException {
16 | synchronized(myMonitorObject){
17 | while(!wasSignalled){
18 | myMonitorObject.wait();
19 | }
20 | //clear signal and continue running.
21 | wasSignalled = false;
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class ThreadSignalingExample {
4 |
5 | public static void main(String[] args) {
6 |
7 | SignalCarrier signalCarrier = new SignalCarrier();
8 |
9 | Thread waiter = new Thread( () -> {
10 | try {
11 | signalCarrier.doWait();
12 | } catch (InterruptedException e) {
13 | e.printStackTrace();
14 | }
15 | });
16 |
17 | Thread notifier = new Thread( () -> {
18 | signalCarrier.doNotify();
19 | });
20 |
21 | notifier.start();
22 | waiter.start();
23 |
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample2.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class ThreadSignalingExample2 {
4 |
5 | public static void main(String[] args) {
6 |
7 | SignalHolder signalHolder = new SignalHolder();
8 |
9 | Thread waiter = new Thread( () -> {
10 | try {
11 | signalHolder.doWait();
12 | } catch (InterruptedException e) {
13 | e.printStackTrace();
14 | }
15 | });
16 |
17 |
18 | Thread notifier = new Thread( () -> {
19 | signalHolder.doNotify();
20 | });
21 |
22 |
23 | waiter.start();
24 | notifier.start();
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample3.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class ThreadSignalingExample3 {
4 |
5 | public static void main(String[] args) {
6 |
7 | SignalCounter signalCounter = new SignalCounter();
8 |
9 | Thread waiter = new Thread( () -> {
10 | for(int i=0; i<100; i++) {
11 | try {
12 | signalCounter.doWait();
13 | } catch (InterruptedException e) {
14 | e.printStackTrace();
15 | }
16 | }
17 | });
18 |
19 | Thread notifier = new Thread( () -> {
20 | for(int i=0; i<100; i++) {
21 | signalCounter.doNotify();
22 | }
23 | });
24 |
25 | notifier.start();
26 | waiter.start();
27 |
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExample4.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | import java.util.concurrent.Semaphore;
4 |
5 | public class ThreadSignalingExample4 {
6 |
7 | public static void main(String[] args) {
8 |
9 | Object signalObject = new Object();
10 |
11 | Thread waiter = new Thread( () -> {
12 | synchronized(signalObject) {
13 | try {
14 | signalObject.wait();
15 | } catch (InterruptedException e) {
16 | e.printStackTrace();
17 | }
18 | }
19 | });
20 |
21 | Thread notifier = new Thread( () -> {
22 | synchronized (signalObject) {
23 | signalObject.notifyAll();
24 | }
25 | });
26 |
27 | notifier.start();
28 | waiter.start();
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/threadsignaling/ThreadSignalingExampleBasic.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.threadsignaling;
2 |
3 | public class ThreadSignalingExampleBasic {
4 |
5 | public static void main(String[] args) {
6 |
7 | Object signalObject = new Object();
8 |
9 | Thread waitingThread = new Thread( () -> {
10 | synchronized(signalObject) {
11 | try {
12 | signalObject.wait();
13 |
14 | } catch (InterruptedException e) {
15 | e.printStackTrace();
16 | }
17 | }
18 | });
19 |
20 | Thread notifyingThread = new Thread( () -> {
21 | synchronized(signalObject) {
22 | signalObject.notify();
23 | }
24 | });
25 |
26 | waitingThread.start();
27 | notifyingThread.start();
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/virtualthreads/ExecutorServiceVirtualThreadsExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.virtualthreads;
2 |
3 | import java.util.concurrent.*;
4 |
5 | public class ExecutorServiceVirtualThreadsExample {
6 |
7 | public static void main(String[] args) {
8 |
9 | ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
10 |
11 | executor.submit(() -> {
12 | System.out.println("This is a Runnable that is executed by a virtual thread");
13 | });
14 |
15 | Callable callable = new Callable<>() {
16 | @Override
17 | public String call() throws Exception {
18 | System.out.println("Callable executed by virtual thread");
19 | return "Result from Callable";
20 | }
21 | };
22 |
23 | Future futureResult = executor.submit(callable);
24 |
25 | try {
26 | System.out.println(futureResult.get());
27 | } catch (InterruptedException e) {
28 | throw new RuntimeException(e);
29 | } catch (ExecutionException e) {
30 | throw new RuntimeException(e);
31 | }
32 |
33 | executor.shutdown();
34 | try {
35 | executor.awaitTermination(10, TimeUnit.SECONDS);
36 | } catch (InterruptedException e) {
37 | throw new RuntimeException(e);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/virtualthreads/VirtualThreadExample.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.virtualthreads;
2 |
3 | public class VirtualThreadExample {
4 |
5 | public static void main(String[] args) {
6 |
7 | // Example 1: Create Runnable. Create and start virtual thread
8 | Runnable runnable = () -> {
9 | for(int i=0; i<10; i++) {
10 | System.out.println("Index: " + i);
11 | }
12 | };
13 |
14 | Thread vThread1 = Thread.ofVirtual().start(runnable);
15 |
16 |
17 | // Example 2: Create but do not start virtual thread
18 | Thread vThreadUnstarted = Thread.ofVirtual().unstarted(runnable);
19 |
20 |
21 |
22 | vThreadUnstarted.start();
23 |
24 | // Example 4: How to join a virtual thread
25 | try {
26 | vThreadUnstarted.join();
27 | } catch (InterruptedException e) {
28 | e.printStackTrace();
29 | }
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/concurrency/virtualthreads/VirtualThreadExample2.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.concurrency.virtualthreads;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class VirtualThreadExample2 {
7 |
8 | public static void main(String[] args) {
9 |
10 | List vThreads = new ArrayList<>();
11 |
12 | int vThreadCount = 100_000;
13 |
14 | for(int i=0; i {
17 | int result = 1;
18 | for(int j=0; j<10; j++) {
19 | result *= (j + 1);
20 | }
21 | System.out.println("Result[" + vThreadIndex +"]: " + result);
22 | });
23 |
24 | vThreads.add(vThread);
25 | }
26 |
27 | for(int i=0; i cars = new ArrayList<>();
9 | //cars.add(new Truck(3000, 800, 200, 5000));
10 |
11 | cars.add(new Car(1000, 400, 180, 5));
12 | cars.add(new Car(1200, 450, 182, 5));
13 | cars.add(new Car(1500, 480, 150, 7));
14 |
15 | int passengerCapacitySum = sumPassengerCapacityGenerics(cars);
16 | System.out.println("total passenger capacity: " + passengerCapacitySum);
17 | }
18 |
19 | public static int sumPassengerCapacity(List cars) {
20 | int passengerCapacitySum = 0;
21 | for(int i=0; i cars) {
29 | int passengerCapacitySum = 0;
30 | for(int i=0; i cars) {
47 | int passengerCapacitySum = 0;
48 | for(Car car : cars){
49 | passengerCapacitySum += car.getPassengerCapacity();
50 | }
51 | return passengerCapacitySum;
52 | }
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/generics/JavaGenericsExample2.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.generics;
2 |
3 | import java.util.*;
4 |
5 | public class JavaGenericsExample2 {
6 |
7 | public static void main(String[] args) {
8 | List carList = new ArrayList<>();
9 | Set carSet = new HashSet<>();
10 | Map carMap = new HashMap<>();
11 |
12 | for(Car car : carList) {
13 |
14 | }
15 |
16 | for(Car car: carSet) {
17 |
18 | }
19 |
20 | for(String key: carMap.keySet()){
21 |
22 | }
23 |
24 | for(Car car: carMap.values()) {
25 |
26 | }
27 | }
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/generics/Truck.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.generics;
2 |
3 | public class Truck extends Vehicle {
4 |
5 | protected int loadCapacity = 0;
6 |
7 | public Truck(int weight, int length, int width, int loadCapacity) {
8 | super(weight, length, width);
9 | this.loadCapacity = loadCapacity;
10 | }
11 |
12 | public int getLoadCapacity() {
13 | return loadCapacity;
14 | }
15 |
16 | public void setLoadCapacity(int loadCapacity) {
17 | this.loadCapacity = loadCapacity;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/generics/Vehicle.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.generics;
2 |
3 | public class Vehicle {
4 |
5 | protected int weight;
6 | protected int length;
7 | protected int width;
8 |
9 |
10 | public Vehicle() {}
11 |
12 | public Vehicle(int weight, int length, int width) {
13 | this.weight = weight;
14 | this.length = length;
15 | this.width = width;
16 | }
17 |
18 | public int getWeight() {
19 | return weight;
20 | }
21 |
22 | public void setWeight(int weight) {
23 | this.weight = weight;
24 | }
25 |
26 | public int getLength() {
27 | return length;
28 | }
29 |
30 | public void setLength(int length) {
31 | this.length = length;
32 | }
33 |
34 | public int getWidth() {
35 | return width;
36 | }
37 |
38 | public void setWidth(int width) {
39 | this.width = width;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/jenkov/java/switchexp/SwitchExamples.java:
--------------------------------------------------------------------------------
1 | package com.jenkov.java.switchexp;
2 |
3 | public class SwitchExamples {
4 |
5 | public static void main(String[] args) {
6 |
7 | int val = Integer.parseInt("123");
8 |
9 | switch(val) {
10 | case 123 : {
11 | System.out.println("123");
12 | break;
13 | }
14 |
15 | default: {
16 | System.out.println("Default");
17 | }
18 | }
19 |
20 | String result = switch(val) {
21 | case 123 -> "123-1234";
22 |
23 | default -> "Default-Default";
24 | };
25 |
26 | System.out.println(result);
27 |
28 | }
29 |
30 | public static void switchOnType() {
31 |
32 | Integer input = Integer.valueOf(123);
33 |
34 | String result =
35 | switch(input) {
36 | //case Integer.class -> "Integer";
37 | case 123 -> "Low number";
38 | default -> "Unknown";
39 | };
40 | }
41 | }
42 |
--------------------------------------------------------------------------------