├── .gitignore ├── README.md └── src └── com └── vivek ├── concurrentutil ├── LockExample.java ├── SynchronousQueueExample.java ├── PriorityBlockingQueueExample.java ├── LinkedBlockingQueueExample.java ├── ExchangerExample.java ├── ConcurrentMapImplementations.java ├── LinkedBlockingDequeExample.java ├── DelayQueueExample.java ├── ReadWriteLockExample.java ├── SemaphoreExample.java ├── ArrayBlockingQueueExample.java ├── CountDownLatchExample.java ├── CyclicBarrierExample.java ├── ExecutorServiceExample.java ├── ForkJoinPoolExample.java └── AtomicUtils.java └── threading ├── BlockingQueue.java ├── ThreadSafeSingleton.java ├── RunThreadsInAlternateOrderWithoutSync.java ├── ConcurrentStack.java ├── ConnectionPool.java ├── WaitForAllThreadsToFinish.java ├── DeadlockInSingleThreadPool.java ├── CancelFutureTask.java ├── BoundedBufferTest.java ├── BoundedBlockingHashSet.java ├── RunThreadsInOrder.java ├── BoundedBuffer.java ├── Deadlock.java ├── ConditionBoundedBuffer.java ├── CancellablePrimeProducer.java ├── FutureExample.java ├── EvenOddPrinter.java ├── TimeConcurrentExecution.java ├── RunThreadsInAlternateOrder.java ├── FutureTaskPreloader.java ├── BoundedExecutor.java ├── MethodAccessCheckForTwoThreads.java ├── MeasureConcurrentRunTime.java ├── PrintPingPongAlternately.java ├── DeadlockDynamicLockOrdering.java ├── EvenOddPrinterUsingExecutor.java ├── KeepThreadRunning.java ├── RunThreadsInOrderUsingSemaphore.java ├── TumblingWindowCounter.java ├── CollapsedForwarding.java ├── H2O.java ├── CustomThreadPoolExecutor.java └── PrintFizzBuzz.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | target/ 4 | out/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # concurrency-java 2 | Problems on multithreading and concurrency in Java and their solutions 3 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/LockExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | public class LockExample { 7 | 8 | public static void main(String[] args) { 9 | 10 | Lock lock = new ReentrantLock(); 11 | 12 | lock.lock(); 13 | 14 | // critical section 15 | 16 | lock.unlock(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/SynchronousQueueExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | public class SynchronousQueueExample { 4 | 5 | /** 6 | * The SynchronousQueue is a queue that can only contain a single element internally. 7 | * A thread inserting an element into the queue is blocked until another thread takes that element from the queue. 8 | * Likewise, if a thread tries to take an element and no element is currently present, 9 | * that thread is blocked until a thread insert an element into the queue. 10 | */ 11 | public static void main(String[] args) { 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/com/vivek/threading/BlockingQueue.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class BlockingQueue { 7 | 8 | private final List queue = new ArrayList<>(); 9 | private final int SIZE; 10 | 11 | public BlockingQueue(int size) { 12 | this.SIZE = size; 13 | } 14 | 15 | public synchronized void enqueue(T elt) throws InterruptedException { 16 | while (queue.size() == SIZE) { 17 | wait(); 18 | } 19 | if (queue.size() == 0) { 20 | notifyAll(); 21 | } 22 | queue.add(elt); 23 | } 24 | 25 | public synchronized T dequeue() throws InterruptedException { 26 | while (queue.size() == 0) { 27 | wait(); 28 | } 29 | if (queue.size() == SIZE) { 30 | notifyAll(); 31 | } 32 | return queue.remove(0); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/com/vivek/threading/ThreadSafeSingleton.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * Created by VJaiswal on 14/05/18. 8 | */ 9 | public class ThreadSafeSingleton { 10 | 11 | private static Lock lock = new ReentrantLock(); 12 | 13 | private static ThreadSafeSingleton INSTANCE; 14 | 15 | private ThreadSafeSingleton() { 16 | } 17 | 18 | public static ThreadSafeSingleton getInstance() { 19 | if (INSTANCE == null) { 20 | lock.lock(); 21 | /* If two threads simultaneously check and pass the first “if” 22 | condition, then only the one who acquired the lock first 23 | should create the instance */ 24 | if (INSTANCE == null) { 25 | INSTANCE = new ThreadSafeSingleton(); 26 | } 27 | lock.unlock(); 28 | } 29 | return INSTANCE; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/PriorityBlockingQueueExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.PriorityBlockingQueue; 5 | 6 | public class PriorityBlockingQueueExample { 7 | 8 | /** 9 | * The PriorityBlockingQueue is an unbounded concurrent queue. It uses the same ordering rules as the java.util.PriorityQueue class. 10 | * You cannot insert null into this queue. 11 | * 12 | * All elements inserted into the PriorityBlockingQueue must implement the java.lang.Comparable interface. 13 | * The elements thus order themselves according to whatever priority you decide in your Comparable implementation. 14 | */ 15 | public static void main(String[] args) { 16 | 17 | BlockingQueue unbounded = new PriorityBlockingQueue(); 18 | 19 | try { 20 | unbounded.put("Value"); 21 | String value = unbounded.take(); 22 | } catch (InterruptedException e) { 23 | e.printStackTrace(); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/LinkedBlockingQueueExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | 6 | /* 7 | BlockingQueue Implementations are 8 | - ArrayBlockingQueue 9 | - DelayQueue 10 | - LinkedBlockingQueue 11 | - PriorityBlockingQueue 12 | - SynchronousQueue 13 | */ 14 | public class LinkedBlockingQueueExample { 15 | 16 | /** 17 | * The LinkedBlockingQueue keeps the elements internally in a linked structure (linked nodes). 18 | * This linked structure can optionally have an upper bound if desired. 19 | * If no upper bound is specified, Integer.MAX_VALUE is used as the upper bound. 20 | */ 21 | public static void main(String[] args) { 22 | 23 | BlockingQueue unbounded = new LinkedBlockingQueue(); 24 | BlockingQueue bounded = new LinkedBlockingQueue(1024); 25 | 26 | try { 27 | bounded.put("Value"); 28 | String value = bounded.take(); 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/com/vivek/threading/RunThreadsInAlternateOrderWithoutSync.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | public class RunThreadsInAlternateOrderWithoutSync implements Runnable { 4 | 5 | private static final int LIMIT = 100; 6 | private static int NB_THREADS = 0; 7 | private int threadId; 8 | private static volatile int counter = 1; 9 | 10 | public RunThreadsInAlternateOrderWithoutSync() { 11 | threadId = NB_THREADS++; 12 | // System.out.println("Thread " + threadId + " started..."); 13 | } 14 | 15 | @Override 16 | public void run() { 17 | outer: 18 | while (counter < LIMIT) { 19 | while (counter % NB_THREADS != threadId) { 20 | if (counter == LIMIT) 21 | break outer; 22 | } 23 | try { 24 | Thread.sleep(200); 25 | } catch (InterruptedException e) { 26 | e.printStackTrace(); 27 | } 28 | System.out.println("Thread-" + threadId + " = " + counter); 29 | counter += 1; 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | 35 | for (int i = 0; i < 10; i++) { 36 | new Thread(new RunThreadsInAlternateOrderWithoutSync()).start(); 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/vivek/threading/ConcurrentStack.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.atomic.AtomicReference; 4 | 5 | /** 6 | * Created by VJaiswal on 25/08/17. 7 | */ 8 | public class ConcurrentStack { 9 | private final AtomicReference> top = new AtomicReference<>(); 10 | 11 | public void push(E elem) { 12 | Node newHead = new Node<>(elem); 13 | Node oldHead; 14 | do { 15 | oldHead = top.get(); 16 | newHead.next = oldHead; 17 | } while (!top.compareAndSet(oldHead, newHead)); 18 | } 19 | 20 | public E pop() { 21 | Node oldHead; 22 | Node newHead; 23 | do { 24 | oldHead = top.get(); 25 | if (oldHead == null) 26 | return null; 27 | newHead = oldHead.next; 28 | } while(!top.compareAndSet(oldHead, newHead)); 29 | return oldHead.item; 30 | } 31 | 32 | private static class Node { 33 | public final E item; 34 | public Node next; 35 | 36 | public Node(E item) { 37 | this.item = item; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/vivek/threading/ConnectionPool.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.sql.Connection; 4 | import java.util.concurrent.ArrayBlockingQueue; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | public class ConnectionPool { 10 | 11 | private BlockingQueue connPool = new ArrayBlockingQueue(10); 12 | private AtomicInteger connCount = new AtomicInteger(); 13 | 14 | public Connection getConnection() throws Exception { 15 | Connection conn = null; 16 | try { 17 | conn = connPool.poll(5, TimeUnit.SECONDS); 18 | if (conn == null) { 19 | synchronized(connCount) { 20 | if (connCount.get() < 10) { 21 | conn = getNewConnection(); 22 | connPool.offer(conn); 23 | connCount.incrementAndGet(); 24 | } 25 | } 26 | if (conn == null) { 27 | throw new Exception("Connection Unavailable"); 28 | } 29 | } 30 | } catch (InterruptedException e) { 31 | e.printStackTrace(); 32 | } 33 | return conn; 34 | } 35 | 36 | private Connection getNewConnection() { 37 | return null; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ExchangerExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.Exchanger; 4 | 5 | public class ExchangerExample { 6 | 7 | /* 8 | * Exchanger class represents a kind of rendezvous point where two threads can exchange objects. 9 | */ 10 | public static void main(String[] args) { 11 | Exchanger exchanger = new Exchanger(); 12 | String obj1 = "A"; 13 | String obj2 = "B"; 14 | 15 | new Thread(new ExchangerRunnable(exchanger, obj1)).start(); 16 | new Thread(new ExchangerRunnable(exchanger, obj2)).start(); 17 | } 18 | 19 | static class ExchangerRunnable implements Runnable { 20 | Exchanger exchanger; 21 | Object obj; 22 | 23 | public ExchangerRunnable(Exchanger exchanger, Object obj) { 24 | this.exchanger = exchanger; 25 | this.obj = obj; 26 | } 27 | 28 | public void run() { 29 | try { 30 | Object previous = this.obj; 31 | this.obj = this.exchanger.exchange(this.obj); 32 | 33 | System.out.println(Thread.currentThread().getName() + " exchanged " + previous + " by " + this.obj); 34 | 35 | } catch (InterruptedException e) { 36 | 37 | } 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ConcurrentMapImplementations.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | import java.util.concurrent.ConcurrentMap; 5 | 6 | public class ConcurrentMapImplementations { 7 | 8 | /** 9 | * ConcurrentMap interface represents a Map which is capable of handling concurrent access (puts and gets) to it. 10 | * 11 | * ConcurrentHashMap is the only implementation of ConcurrentMap 12 | * 13 | * ConcurrentHashMap does not lock the Map while you are reading from it. 14 | * Additionally, ConcurrentHashMap does not lock the entire Map when writing to it. 15 | * It only locks the part of the Map that is being written to, internally. 16 | * 17 | * Another difference is that ConcurrentHashMap does not throw ConcurrentModificationException 18 | * if the ConcurrentHashMap is changed while being iterated. The Iterator is not designed to be used by more than one thread though. 19 | */ 20 | public static void main(String[] args) { 21 | 22 | ConcurrentMap concurrentMap = new ConcurrentHashMap(); 23 | 24 | concurrentMap.put("key", "value"); 25 | Object value = concurrentMap.get("key"); 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/LinkedBlockingDequeExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.BlockingDeque; 4 | import java.util.concurrent.LinkedBlockingDeque; 5 | 6 | public class LinkedBlockingDequeExample { 7 | 8 | /** 9 | * A BlockingDeque could be used if threads are both producing and consuming elements of the same queue. 10 | * It could also just be used if the producing thread needs to insert at both ends of the queue, 11 | * and the consuming thread needs to remove from both ends of the queue. 12 | * 13 | * A thread will produce elements and insert them into either end of the queue. 14 | * If the deque is currently full, the inserting thread will be blocked until a removing thread takes an element out of the deque. 15 | * If the deque is currently empty, a removing thread will be blocked until an inserting thread inserts an element into the deque. 16 | */ 17 | public static void main(String[] args) throws InterruptedException { 18 | 19 | BlockingDeque deque = new LinkedBlockingDeque(); 20 | 21 | deque.addFirst("1"); 22 | deque.addLast("2"); 23 | 24 | String two = deque.takeLast(); 25 | String one = deque.takeFirst(); 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/com/vivek/threading/WaitForAllThreadsToFinish.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class WaitForAllThreadsToFinish { 7 | 8 | static class MyThread extends Thread { 9 | private int countDown = 10; 10 | private static int threadCount = 0; 11 | private int threadNumber = ++threadCount; 12 | 13 | public void run() { 14 | while (true) { 15 | System.out.println("Thread " + threadNumber + "(" + countDown + ")"); 16 | try { 17 | sleep(500); 18 | } 19 | catch (InterruptedException e) { 20 | e.printStackTrace(); 21 | } 22 | if (--countDown == 0) 23 | return; 24 | } 25 | } 26 | 27 | } 28 | 29 | public static void main(String... args) { 30 | 31 | List threads = new ArrayList<>(); 32 | for (int i = 0; i < 10; i++) { 33 | MyThread thread = new MyThread(); 34 | thread.start(); 35 | threads.add(thread); 36 | } 37 | 38 | 39 | for (MyThread thread : threads) { 40 | try { 41 | thread.join(); 42 | } catch (InterruptedException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | System.out.println("All Threads Started and ran. Exiting :) "); 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/vivek/threading/DeadlockInSingleThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | 7 | /** 8 | * Created by VJaiswal on 05/08/17. 9 | */ 10 | public class DeadlockInSingleThreadPool { 11 | 12 | private static ExecutorService exec = Executors.newSingleThreadExecutor(); 13 | 14 | public static void main(String[] args) { 15 | Runnable task2 = () -> { 16 | System.out.println("Started task 2"); 17 | System.out.println("Working"); 18 | System.out.println("Working"); 19 | System.out.println("Finished task 2"); 20 | }; 21 | 22 | Runnable task1 = () -> { 23 | System.out.println("Started task 1"); 24 | 25 | Future result = exec.submit(task2); 26 | while (!result.isDone()) { 27 | System.out.println("Waiting for task 2 to finish"); 28 | try { 29 | Thread.sleep(2000); 30 | } catch (InterruptedException ignored) {} 31 | } 32 | 33 | System.out.println("Finished task 1"); 34 | }; 35 | 36 | exec.submit(task1); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/vivek/threading/CancelFutureTask.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.*; 4 | 5 | /** 6 | * Created by VJaiswal on 01/08/17. 7 | */ 8 | public class CancelFutureTask { 9 | 10 | public static void timedRun(Runnable r, long timeout, TimeUnit unit) throws Exception { 11 | ExecutorService executor = Executors.newSingleThreadExecutor(); 12 | Future task = executor.submit(r); 13 | try { 14 | task.get(timeout, unit); 15 | } catch (TimeoutException e) { 16 | // cancel task below 17 | } catch (ExecutionException e) { 18 | throw new Exception("Error in execution"); 19 | } finally { 20 | task.cancel(true); 21 | } 22 | } 23 | 24 | public static void main(String[] args) throws Exception { 25 | Runnable task = () -> { 26 | try { 27 | System.out.println("Task Started..."); 28 | Thread.sleep(5000); 29 | System.out.println("Task Finished..."); 30 | } catch (InterruptedException e) { 31 | System.out.println("Task cancelled..."); 32 | } 33 | }; 34 | 35 | CancelFutureTask.timedRun(task, 2000, TimeUnit.MILLISECONDS); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/com/vivek/threading/BoundedBufferTest.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import junit.framework.TestCase; 4 | 5 | /** 6 | * Created by VJaiswal on 20/08/17. 7 | */ 8 | public class BoundedBufferTest extends TestCase { 9 | 10 | public void testIsEmptyWhenConstructed() { 11 | BoundedBuffer bb = new BoundedBuffer<>(10); 12 | assertTrue(bb.isEmpty()); 13 | assertFalse(bb.isFull()); 14 | } 15 | 16 | public void testIsFullAfterPuts() throws InterruptedException { 17 | BoundedBuffer bb = new BoundedBuffer<>(10); 18 | for (int i = 0; i < 10; i++) { 19 | bb.put(i); 20 | } 21 | assertFalse(bb.isEmpty()); 22 | assertTrue(bb.isFull()); 23 | } 24 | 25 | public void testTakeBlocksWhenEmpty() throws InterruptedException { 26 | final long TIME_TO_WAIT = 10000; 27 | BoundedBuffer bb = new BoundedBuffer<>(10); 28 | Thread takerThread = new Thread(() -> { 29 | try { 30 | bb.take(); 31 | fail(); 32 | } catch (InterruptedException success) {} 33 | }); 34 | takerThread.start(); 35 | Thread.sleep(TIME_TO_WAIT); 36 | takerThread.interrupt(); 37 | Thread.sleep(TIME_TO_WAIT); 38 | takerThread.join(); 39 | assertFalse(takerThread.isAlive()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/com/vivek/threading/BoundedBlockingHashSet.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.concurrent.Semaphore; 6 | 7 | /** 8 | * Created by VJaiswal on 29/07/17. 9 | */ 10 | public class BoundedBlockingHashSet { 11 | private Set set; 12 | private Semaphore sem; 13 | 14 | public BoundedBlockingHashSet(int bound) { 15 | set = new HashSet<>(); 16 | sem = new Semaphore(bound); 17 | } 18 | 19 | public boolean add(T o) throws InterruptedException { 20 | sem.acquire(); 21 | boolean isAdded = false; 22 | try { 23 | isAdded = set.add(o); 24 | } finally { 25 | if (!isAdded) { 26 | sem.release(); 27 | } 28 | } 29 | return isAdded; 30 | } 31 | 32 | public boolean remove(T o) throws InterruptedException { 33 | boolean isRemoved = set.remove(o); 34 | if (isRemoved) { 35 | sem.release(); 36 | } 37 | return isRemoved; 38 | } 39 | 40 | public static void main(String[] args) throws Exception { 41 | BoundedBlockingHashSet set = new BoundedBlockingHashSet<>(5); 42 | set.add("Hi"); 43 | set.add("Hola"); 44 | set.add("Hello"); 45 | set.add("Hey"); 46 | set.add("Bonjour"); 47 | // set.add("Ciao"); 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/DelayQueueExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.DelayQueue; 5 | import java.util.concurrent.Delayed; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class DelayQueueExample { 9 | 10 | /* 11 | BlockingQueue Implementations are 12 | - ArrayBlockingQueue 13 | - DelayQueue 14 | - LinkedBlockingQueue 15 | - PriorityBlockingQueue 16 | - SynchronousQueue 17 | */ 18 | public static void main(String[] args) { 19 | /* 20 | * The DelayQueue blocks the elements internally until a certain delay has expired. 21 | * The elements must implement the interface java.util.concurrent.Delayed. Here is how the interface looks: 22 | * 23 | * interface Delayed extends Comparable { 24 | public long getDelay(TimeUnit timeUnit); 25 | } 26 | */ 27 | BlockingQueue delayQueue = new DelayQueue(); 28 | try { 29 | delayQueue.put(new MyDelayed(1)); 30 | Delayed elt = (MyDelayed) delayQueue.take(); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | 35 | } 36 | 37 | static class MyDelayed implements Delayed { 38 | private int num; 39 | 40 | public MyDelayed(int num) { 41 | this.num = num; 42 | } 43 | 44 | public long getDelay(TimeUnit timeUnit) { 45 | return 100; 46 | } 47 | 48 | @Override 49 | public int compareTo(Delayed o) { 50 | MyDelayed other = (MyDelayed) o; 51 | return (this.num == other.num) ? 0 : (this.num > other.num) ? 1 : -1; 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/vivek/threading/RunThreadsInOrder.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | public class RunThreadsInOrder implements Runnable { 4 | 5 | private int threadID; 6 | static int threadToRun = 1; 7 | static int numThread = 1; 8 | 9 | private static Object myLock = new Object(); 10 | 11 | public RunThreadsInOrder() { 12 | this.threadID = numThread++; 13 | System.out.println("Thread ID: " + threadID); 14 | } 15 | 16 | public void run() { 17 | synchronized (myLock) { 18 | while (threadID != threadToRun) { 19 | try { 20 | myLock.wait(); 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } 24 | } 25 | try { 26 | Thread.sleep(1000); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | System.out.println("MyThread is running: " + threadID); 32 | myLock.notifyAll(); 33 | threadToRun++; 34 | } 35 | } 36 | 37 | public static void main(String... args) { 38 | 39 | Thread t1 = new Thread(new RunThreadsInOrder()); 40 | Thread t2 = new Thread(new RunThreadsInOrder()); 41 | Thread t3 = new Thread(new RunThreadsInOrder()); 42 | Thread t4 = new Thread(new RunThreadsInOrder()); 43 | Thread t5 = new Thread(new RunThreadsInOrder()); 44 | Thread t6 = new Thread(new RunThreadsInOrder()); 45 | Thread t7 = new Thread(new RunThreadsInOrder()); 46 | 47 | t7.start(); 48 | t6.start(); 49 | t5.start(); 50 | t4.start(); 51 | t3.start(); 52 | t2.start(); 53 | t1.start(); 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/com/vivek/threading/BoundedBuffer.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | /** 6 | * Created by VJaiswal on 20/08/17. 7 | */ 8 | public class BoundedBuffer { 9 | private final Semaphore availableItems, availableSpaces; 10 | private int takePosition, putPosition; 11 | private final T[] elements; 12 | 13 | public BoundedBuffer(int capacity) { 14 | elements = (T[]) new Object[capacity]; 15 | availableItems = new Semaphore(0); 16 | availableSpaces = new Semaphore(capacity); 17 | } 18 | 19 | public boolean isEmpty() { 20 | return availableItems.availablePermits() == 0; 21 | } 22 | 23 | public boolean isFull() { 24 | return availableSpaces.availablePermits() == 0; 25 | } 26 | 27 | public void put(T elem) throws InterruptedException { 28 | availableSpaces.acquire(); 29 | doInsert(elem); 30 | availableItems.release(); 31 | } 32 | 33 | public T take() throws InterruptedException { 34 | availableItems.acquire(); 35 | T elem = doGet(); 36 | availableSpaces.release(); 37 | return elem; 38 | } 39 | 40 | private synchronized T doGet() { 41 | int i = takePosition; 42 | T elem = elements[i]; 43 | takePosition = ++i == elements.length ? 0 : i; 44 | return elem; 45 | } 46 | 47 | private synchronized void doInsert(T elem) { 48 | int i = putPosition; 49 | elements[i] = elem; 50 | putPosition = ++i == elements.length ? 0 : i; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/com/vivek/threading/Deadlock.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | 8 | /** 9 | * Created by VJaiswal on 12/06/17. 10 | */ 11 | public class Deadlock { 12 | 13 | public static void main(String[] args) { 14 | 15 | A objA = new A(); 16 | objA.add(new B() { 17 | 18 | public void added(final A a) { 19 | System.out.println("Overridden"); 20 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 21 | final B objB = this; 22 | try { 23 | executorService.submit(() -> a.remove(objB)).get(); 24 | } catch (Exception e) { 25 | e.printStackTrace(); 26 | } finally { 27 | executorService.shutdown(); 28 | } 29 | } 30 | }); 31 | 32 | } 33 | 34 | static class A { 35 | 36 | private final List elements = new ArrayList<>(); 37 | 38 | public void add(B elt) { 39 | synchronized (elements) { 40 | elements.add(elt); 41 | } 42 | } 43 | 44 | public void remove(B elt) { 45 | synchronized (elements) { 46 | elements.remove(elt); 47 | } 48 | } 49 | } 50 | 51 | static class B { 52 | 53 | public void added(final A a) { 54 | System.out.println("No override"); 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ReadWriteLockExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.locks.ReadWriteLock; 4 | import java.util.concurrent.locks.ReentrantReadWriteLock; 5 | 6 | public class ReadWriteLockExample { 7 | 8 | /* 9 | * ReadWriteLock is an advanced thread lock mechanism. It allows multiple threads to read a certain resource, but only one to write it, at a time. 10 | * 11 | * The idea is, that multiple threads can read from a shared resource without causing concurrency errors. 12 | * The concurrency errors first occur when reads and writes to a shared resource occur concurrently, or if multiple writes take place concurrently. 13 | * 14 | * Read Lock : If no threads have locked the ReadWriteLock for writing, and no thread have requested a write lock (but not yet obtained it). Thus, multiple threads can lock the lock for reading. 15 | * Write Lock : If no threads are reading or writing. Thus, only one thread at a time can lock the lock for writing. 16 | */ 17 | public static void main(String[] args) { 18 | 19 | ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 20 | 21 | 22 | readWriteLock.readLock().lock(); 23 | 24 | // multiple readers can enter this section 25 | // if not locked for writing, and no writers waiting 26 | // to lock for writing. 27 | 28 | readWriteLock.readLock().unlock(); 29 | 30 | 31 | readWriteLock.writeLock().lock(); 32 | 33 | // only one writer can enter this section, 34 | // and only if no threads are currently reading. 35 | 36 | readWriteLock.writeLock().unlock(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/com/vivek/threading/ConditionBoundedBuffer.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.locks.Condition; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | /** 8 | * Created by VJaiswal on 25/08/17. 9 | */ 10 | public class ConditionBoundedBuffer { 11 | 12 | protected final Lock lock = new ReentrantLock(); 13 | private final Condition notFull = lock.newCondition(); 14 | private final Condition notEmpty = lock.newCondition(); 15 | 16 | private final T[] items = (T[]) new Object[10]; 17 | private int head, tail, count; 18 | 19 | public void put(T elem) throws InterruptedException { 20 | lock.lock(); 21 | try { 22 | while (count == items.length) { 23 | notFull.await(); 24 | } 25 | items[tail] = elem; 26 | if (++tail == items.length) { 27 | tail = 0; 28 | } 29 | ++count; 30 | notEmpty.signal(); 31 | } finally { 32 | lock.unlock(); 33 | } 34 | } 35 | 36 | public T take() throws InterruptedException { 37 | lock.lock(); 38 | try { 39 | while (count == 0) { 40 | notEmpty.await(); 41 | } 42 | T elem = items[head]; 43 | items[head] = null; 44 | if (++head == items.length) { 45 | head = 0; 46 | } 47 | --count; 48 | notFull.signal(); 49 | return elem; 50 | } finally { 51 | lock.unlock(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/com/vivek/threading/CancellablePrimeProducer.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.math.BigInteger; 4 | import java.util.concurrent.ArrayBlockingQueue; 5 | import java.util.concurrent.BlockingQueue; 6 | 7 | /** 8 | * Created by VJaiswal on 31/07/17. 9 | */ 10 | public class CancellablePrimeProducer extends Thread { 11 | 12 | private BlockingQueue queue; 13 | 14 | public CancellablePrimeProducer(BlockingQueue queue) { 15 | this.queue = queue; 16 | } 17 | 18 | @Override 19 | public void run() { 20 | try { 21 | BigInteger p = BigInteger.ONE; 22 | while (!Thread.currentThread().isInterrupted()) { 23 | queue.put(p = p.nextProbablePrime()); 24 | } 25 | System.out.println("Thread interrupted status received"); 26 | } catch (InterruptedException e) { 27 | System.err.println("Thread interrupted exception received"); 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | public void cancel() { 33 | interrupt(); 34 | } 35 | 36 | public static void main(String[] args) throws Exception { 37 | // ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); 38 | BlockingQueue queue = new ArrayBlockingQueue<>(10000); 39 | 40 | CancellablePrimeProducer producer = new CancellablePrimeProducer(queue); 41 | // scheduler.schedule(() -> producer.cancel(), 2, TimeUnit.SECONDS); 42 | producer.start(); 43 | 44 | Thread.sleep(2000); 45 | 46 | producer.cancel(); 47 | 48 | Thread.sleep(1000); 49 | 50 | while (!queue.isEmpty()) 51 | System.out.println(queue.take()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/SemaphoreExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | public class SemaphoreExample { 6 | 7 | /* 8 | * The java.util.concurrent.Semaphore class is a counting semaphore. That means that it has two main methods: 9 | 10 | - acquire() 11 | - release() 12 | 13 | The counting semaphore is initialized with a given number of "permits". 14 | For each call to acquire() a permit is taken by the calling thread. For each call to release() a permit is returned to the semaphore. 15 | Thus, at most N threads can pass the acquire() method without any release() calls, 16 | where N is the number of permits the semaphore was initialized with. 17 | The permits are just a simple counter. Nothing fancy here. 18 | 19 | As semaphore typically has two uses: 20 | 21 | - To guard a critical section against entry by more than N threads at a time. 22 | - To send signals between two threads. 23 | */ 24 | public static void main(String[] args) { 25 | 26 | /* 27 | * Guarding Critical Section 28 | */ 29 | Semaphore semaphore = new Semaphore(1); 30 | 31 | //critical section 32 | try { 33 | semaphore.acquire(); 34 | 35 | /// 36 | 37 | semaphore.release(); 38 | 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | 43 | /* 44 | 45 | If you use a semaphore to send signals between threads, then you would typically have one thread call the acquire() method, and the other thread to call the release() method. 46 | 47 | If no permits are available, the acquire() call will block until a permit is released by another thread. Similarly, a release() call is blocked if no more permits can be released into this semaphore. 48 | 49 | */ 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/com/vivek/threading/FutureExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.*; 4 | 5 | public class FutureExample { 6 | 7 | private static final ExecutorService threadpool = Executors.newFixedThreadPool(3); 8 | 9 | public static void main(String args[]) throws InterruptedException, ExecutionException { 10 | FactorialCalculator task = new FactorialCalculator(10); 11 | System.out.println("Submitting Task ..."); 12 | Future future = threadpool.submit(task); 13 | System.out.println("Task is submitted"); 14 | 15 | while (!future.isDone()) { 16 | System.out.println("Task is not completed yet...."); 17 | Thread.sleep(1); //sleep for 1 millisecond before checking again 18 | } 19 | System.out.println("Task is completed, let's check result"); 20 | long factorial = future.get(); 21 | System.out.println("Factorial of 1000000 is : " + factorial); 22 | threadpool.shutdown(); 23 | } 24 | 25 | private static class FactorialCalculator implements Callable { 26 | private final int number; 27 | public FactorialCalculator(int number) { 28 | this.number = number; 29 | } 30 | 31 | @Override 32 | public Long call() { 33 | long output = 0; 34 | try { 35 | output = factorial(number); 36 | } catch (InterruptedException ex) { 37 | ex.printStackTrace(); 38 | } 39 | return output; 40 | } 41 | 42 | 43 | private long factorial(int number) throws InterruptedException { 44 | if (number < 0) { 45 | throw new IllegalArgumentException("Number must be greater than zero"); 46 | } 47 | long result = 1; 48 | while (number > 0) { 49 | Thread.sleep(1); // adding delay for example 50 | result = result * number; 51 | number--; 52 | } 53 | return result; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/vivek/threading/EvenOddPrinter.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | public class EvenOddPrinter { 4 | 5 | private final Object lock = new Object(); 6 | private static final int MAX = 10; 7 | private boolean evenTurn = false; 8 | 9 | public static void main(String[] args) throws Exception { 10 | EvenOddPrinter printer = new EvenOddPrinter(); 11 | Thread oddThread = new Thread(printer::printOdd); 12 | Thread evenThread = new Thread(printer::printEven); 13 | 14 | oddThread.start(); 15 | evenThread.start(); 16 | } 17 | 18 | public void printEven() { 19 | for (int i = 2; i <= MAX; i += 2) { 20 | synchronized(lock) { 21 | while (!evenTurn) { 22 | try { 23 | lock.wait(); 24 | } catch (InterruptedException ex) { 25 | Thread.currentThread().interrupt(); 26 | return; 27 | } 28 | } 29 | System.out.println("Even: " + i); 30 | evenTurn = false; 31 | lock.notify(); 32 | } 33 | } 34 | } 35 | 36 | public void printOdd() { 37 | for (int i = 1; i <= MAX; i += 2) { 38 | synchronized(lock) { 39 | while (evenTurn) { 40 | try { 41 | lock.wait(); 42 | } catch (InterruptedException ex) { 43 | Thread.currentThread().interrupt(); 44 | return; 45 | } 46 | } 47 | System.out.println("Odd: " + i); 48 | evenTurn = true; 49 | lock.notify(); 50 | } 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/com/vivek/threading/TimeConcurrentExecution.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.Executor; 5 | import java.util.concurrent.Executors; 6 | 7 | /** 8 | * Created by VJaiswal on 12/06/17. 9 | * 10 | * simple framework for timing the concurrent execution of an action 11 | */ 12 | public class TimeConcurrentExecution { 13 | 14 | public static void main(String[] args) throws Exception { 15 | Runnable action = () -> System.out.println("Running action..."); 16 | System.out.println(time(Executors.newFixedThreadPool(10), 5, action)); 17 | } 18 | 19 | public static long time(Executor executor, int concurrency, final Runnable action) throws InterruptedException { 20 | final CountDownLatch ready = new CountDownLatch(concurrency); 21 | final CountDownLatch start = new CountDownLatch(1); 22 | final CountDownLatch done = new CountDownLatch(concurrency); 23 | 24 | for (int i = 0; i < concurrency; i++) { 25 | executor.execute( () -> { 26 | ready.countDown(); // Tell timer we're ready 27 | try { 28 | start.await(); // Wait till peers are ready 29 | action.run(); 30 | } catch (InterruptedException e) { 31 | Thread.currentThread().interrupt(); 32 | } finally { 33 | done.countDown(); // Tell timer we're done 34 | } 35 | 36 | }); 37 | } 38 | ready.await(); // Wait for all workers to be ready 39 | long startNanos = System.nanoTime(); 40 | start.countDown(); // And they're off 41 | done.await(); // Wait for all workers to finish 42 | 43 | return System.nanoTime() - startNanos; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/com/vivek/threading/RunThreadsInAlternateOrder.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | public class RunThreadsInAlternateOrder implements Runnable { 4 | 5 | private int threadId; 6 | static int threadNumber = 1; 7 | static int countDown = 1; 8 | 9 | private static Object myLock = new Object(); 10 | 11 | public RunThreadsInAlternateOrder() { 12 | this.threadId = threadNumber++; 13 | System.out.println("Thread " + threadId + " running..."); 14 | } 15 | 16 | public void run() { 17 | synchronized (myLock) { 18 | while (countDown % threadNumber != threadId) { 19 | try { 20 | myLock.wait(); 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } 24 | } 25 | 26 | try { 27 | Thread.sleep(200); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | 32 | System.out.println("Thread-" + threadId + " - Count - " + (countDown++)); 33 | myLock.notifyAll(); 34 | } 35 | } 36 | 37 | public static void main(String... args) { 38 | for (int i = 0; i < 20; i++) { 39 | Thread t = new Thread(new RunThreadsInAlternateOrder()); 40 | t.start(); 41 | } 42 | 43 | // Thread t1 = new Thread(new RunThreadsInAlternateOrder()); 44 | // Thread t2 = new Thread(new RunThreadsInAlternateOrder()); 45 | // Thread t3 = new Thread(new RunThreadsInAlternateOrder()); 46 | // Thread t4 = new Thread(new RunThreadsInAlternateOrder()); 47 | // Thread t5 = new Thread(new RunThreadsInAlternateOrder()); 48 | // Thread t6 = new Thread(new RunThreadsInAlternateOrder()); 49 | // Thread t7 = new Thread(new RunThreadsInAlternateOrder()); 50 | // 51 | // t7.start(); 52 | // t6.start(); 53 | // t5.start(); 54 | // t4.start(); 55 | // t3.start(); 56 | // t2.start(); 57 | // t1.start(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/com/vivek/threading/FutureTaskPreloader.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.FutureTask; 4 | 5 | /** 6 | * Created by VJaiswal on 29/01/17. 7 | */ 8 | public class FutureTaskPreloader { 9 | 10 | private final FutureTask future = new FutureTask( 11 | () -> {return getProduct();} 12 | ); 13 | 14 | private final Thread t = new Thread(future); 15 | 16 | public void start() { 17 | t.start(); 18 | } 19 | 20 | public ProductInfo get() throws Exception { 21 | try { 22 | return future.get(); 23 | } catch (Exception e) { 24 | Throwable cause = e.getCause(); 25 | if (cause instanceof Error) { 26 | System.out.println("Its an error"); 27 | } else if (cause instanceof RuntimeException) { 28 | System.out.println("Its a runtime error"); 29 | } else { 30 | System.out.println("Some exception"); 31 | } 32 | throw e; 33 | } 34 | } 35 | 36 | private static ProductInfo getProduct() { 37 | return new ProductInfo("Macbook", 234567L, 565.5f); 38 | } 39 | 40 | static class ProductInfo { 41 | private String name; 42 | private long id; 43 | private float price; 44 | 45 | public ProductInfo(String name, long id, float price) { 46 | this.name = name; 47 | this.id = id; 48 | this.price = price; 49 | } 50 | 51 | public String toString() { 52 | return "[ name : {" + name + "}, id : {" + id + "}, price : {" + price + "} ]"; 53 | } 54 | } 55 | 56 | public static void main(String... args) throws Exception { 57 | FutureTaskPreloader loader = new FutureTaskPreloader(); 58 | loader.start(); 59 | System.out.println(loader.get()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ArrayBlockingQueueExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.*; 4 | 5 | public class ArrayBlockingQueueExample { 6 | 7 | /* 8 | BlockingQueue Implementations are 9 | - ArrayBlockingQueue 10 | - DelayQueue 11 | - LinkedBlockingQueue 12 | - PriorityBlockingQueue 13 | - SynchronousQueue 14 | */ 15 | public static void main(String[] args) { 16 | BlockingQueue queue = new ArrayBlockingQueue(10); // ArrayBlockingQueue is a bounded, There is an upper bound on the number of elements it can store at the same time. You set the upper bound at instantiation time, and after that it cannot be changed. 17 | Producer p = new Producer(queue); 18 | Consumer c = new Consumer(queue); 19 | 20 | ExecutorService es = Executors.newFixedThreadPool(2); 21 | es.execute(p); 22 | es.execute(c); 23 | 24 | if (null != es) { 25 | es.shutdown(); 26 | try { 27 | es.awaitTermination(5000, TimeUnit.SECONDS); 28 | } catch (InterruptedException e) { 29 | Thread.currentThread().interrupted(); 30 | } 31 | } 32 | } 33 | 34 | static class Producer implements Runnable { 35 | protected BlockingQueue queue; 36 | 37 | public Producer(BlockingQueue queue) { 38 | this.queue = queue; 39 | } 40 | 41 | public void run() { 42 | try { 43 | queue.put(1); 44 | Thread.sleep(2000); 45 | queue.put(2); 46 | Thread.sleep(2000); 47 | queue.put(3); 48 | } catch (InterruptedException e) { 49 | 50 | } 51 | } 52 | } 53 | 54 | static class Consumer implements Runnable { 55 | protected BlockingQueue queue; 56 | 57 | public Consumer(BlockingQueue queue) { 58 | this.queue = queue; 59 | } 60 | 61 | public void run() { 62 | try { 63 | System.out.println(queue.take()); 64 | System.out.println(queue.take()); 65 | System.out.println(queue.take()); 66 | } catch (InterruptedException e) { 67 | 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/com/vivek/threading/BoundedExecutor.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.*; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | /** 7 | * Created by VJaiswal on 07/08/17. 8 | */ 9 | public class BoundedExecutor { 10 | 11 | private Executor executor; 12 | private Semaphore semaphore; 13 | 14 | public BoundedExecutor(Executor executor, int bound) { 15 | this.executor = executor; 16 | this.semaphore = new Semaphore(bound); 17 | } 18 | 19 | public void submitTask(final Runnable command) throws InterruptedException { 20 | semaphore.acquire(); 21 | try { 22 | executor.execute(() -> { 23 | try { 24 | command.run(); 25 | } finally { 26 | semaphore.release(); 27 | } 28 | }); 29 | } catch (RejectedExecutionException e) { 30 | semaphore.release(); 31 | } 32 | } 33 | 34 | public static void main(String[] args) throws Exception { 35 | ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 36 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); 37 | BoundedExecutor boundedExecutor = new BoundedExecutor(executor, 4); 38 | AtomicInteger counter = new AtomicInteger(0); 39 | Runnable task = () -> { 40 | try { 41 | final int id = counter.incrementAndGet(); 42 | System.out.println("Task " + id + " started"); 43 | Thread.sleep(20000); 44 | System.out.println("Task " + id + " finished"); 45 | } catch (InterruptedException ignored) {} 46 | }; 47 | for (int i = 0; i < 10; i++) { 48 | boundedExecutor.submitTask(task); 49 | } 50 | 51 | executor.shutdown(); 52 | executor.awaitTermination(1, TimeUnit.HOURS); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/com/vivek/threading/MethodAccessCheckForTwoThreads.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | /** 4 | * Created by VJaiswal on 29/03/17. 5 | */ 6 | public class MethodAccessCheckForTwoThreads { 7 | 8 | synchronized static void methodA() { 9 | System.out.println(Thread.currentThread().getName() + "executing"); 10 | System.out.println("In method A"); 11 | 12 | for (int i = 0; i < 100; i++) { 13 | System.out.print(i + ", "); 14 | } 15 | System.out.println(); 16 | 17 | System.out.println("Exiting A"); 18 | } 19 | 20 | synchronized void methodB() { 21 | System.out.println(Thread.currentThread().getName() + "executing"); 22 | System.out.println("In method B"); 23 | 24 | for (int i = 0; i < 100; i++) { 25 | System.out.print(i + ", "); 26 | } 27 | System.out.println(); 28 | 29 | System.out.println("Exiting B"); 30 | } 31 | 32 | public static void main(String[] args) { 33 | MethodAccessCheckForTwoThreads o = new MethodAccessCheckForTwoThreads(); 34 | 35 | Runnable r1 = new RunnableA(); 36 | Runnable r2 = new RunnableB(o); 37 | 38 | Thread t1 = new Thread(r1, "t1"); 39 | Thread t2 = new Thread(r2, "t2"); 40 | 41 | Thread t11 = new Thread(r1, "t11"); 42 | Thread t21 = new Thread(r2, "t21"); 43 | 44 | t1.start(); 45 | t11.start(); 46 | // t2.start(); 47 | // t21.start(); 48 | } 49 | 50 | static class RunnableA implements Runnable { 51 | @Override 52 | public void run() { 53 | methodA(); 54 | } 55 | } 56 | 57 | static class RunnableB implements Runnable { 58 | MethodAccessCheckForTwoThreads o; 59 | 60 | public RunnableB(MethodAccessCheckForTwoThreads o) { 61 | this.o = o; 62 | } 63 | 64 | @Override 65 | public void run() { 66 | o.methodB(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/com/vivek/threading/MeasureConcurrentRunTime.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | /** 6 | * Latch is a synchronizer which blocks all the threads until it reaches its terminal state. 7 | * It acts like a Gate. After it reaches its terminal state, it can not change its state. And all the threads can pass. 8 | */ 9 | public class MeasureConcurrentRunTime { 10 | 11 | public void runAndMeasureRunTime(final int nThreads, final Runnable taskToExecute) throws InterruptedException { 12 | final CountDownLatch startLatch = new CountDownLatch(1); 13 | final CountDownLatch endLatch = new CountDownLatch(nThreads); 14 | 15 | for (int i = 0; i < nThreads; i++) { 16 | Runnable r = () -> { 17 | try { 18 | startLatch.await(); 19 | try { 20 | taskToExecute.run(); 21 | } finally { 22 | endLatch.countDown(); 23 | } 24 | } catch (InterruptedException e) {} 25 | }; 26 | Thread t = new Thread(r) ; 27 | t.start(); 28 | } 29 | 30 | long start = System.nanoTime(); 31 | startLatch.countDown(); 32 | endLatch.await(); 33 | long end = System.nanoTime(); 34 | System.out.println(end - start); 35 | 36 | } 37 | 38 | public static void main(String... args) { 39 | MeasureConcurrentRunTime m = new MeasureConcurrentRunTime(); 40 | Runnable task = () -> { 41 | System.out.println("Executing task..."); 42 | try { 43 | Thread.sleep(3000); 44 | } catch (InterruptedException e) {} 45 | finally { 46 | System.out.println("Task finished."); 47 | } 48 | }; 49 | try { 50 | m.runAndMeasureRunTime(5, task); 51 | } catch (InterruptedException e) {} 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/vivek/threading/PrintPingPongAlternately.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public class PrintPingPongAlternately { 8 | private static final int LIMIT = 10; 9 | 10 | public static void main(String[] args) { 11 | ExecutorService es = Executors.newFixedThreadPool(2); 12 | Mutex mutex = new Mutex(); 13 | Mutex.isPing = true; 14 | PingRunnable ping = new PingRunnable(mutex); 15 | PongRunnable pong = new PongRunnable(mutex); 16 | es.execute(ping); 17 | es.execute(pong); 18 | 19 | if (null != es) { 20 | es.shutdown(); 21 | try { 22 | es.awaitTermination(1, TimeUnit.MINUTES); 23 | } catch (InterruptedException e) { 24 | Thread.currentThread().interrupted(); 25 | } 26 | } 27 | } 28 | 29 | static class Mutex { 30 | static boolean isPing; 31 | } 32 | 33 | static class PingRunnable implements Runnable { 34 | private Mutex mutex; 35 | 36 | public PingRunnable(Mutex mutex) { 37 | this.mutex = mutex; 38 | } 39 | 40 | public void run() { 41 | for (int i = 0; i < LIMIT; i++) { 42 | synchronized (mutex) { 43 | while (!Mutex.isPing) { 44 | try { 45 | mutex.wait(); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | System.out.println("Ping"); 51 | Mutex.isPing = false; 52 | mutex.notify(); 53 | } 54 | } 55 | 56 | } 57 | } 58 | 59 | static class PongRunnable implements Runnable { 60 | private Mutex mutex; 61 | 62 | public PongRunnable(Mutex mutex) { 63 | this.mutex = mutex; 64 | } 65 | 66 | public void run() { 67 | for (int i = 0; i < LIMIT; i++) { 68 | synchronized (mutex) { 69 | while (Mutex.isPing) { 70 | try { 71 | mutex.wait(); 72 | } catch (InterruptedException e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | System.out.println("Pong"); 77 | Mutex.isPing = true; 78 | mutex.notify(); 79 | } 80 | } 81 | 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/com/vivek/threading/DeadlockDynamicLockOrdering.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | /** 4 | * Created by VJaiswal on 18/08/17. 5 | */ 6 | public class DeadlockDynamicLockOrdering { 7 | 8 | private final Object tieLock = new Object(); 9 | 10 | public void deadlockProneTransferMoney(Account fromAccount, Account toAccount, int amount) { 11 | synchronized (fromAccount) { 12 | synchronized (toAccount) { 13 | fromAccount.debit(amount); 14 | toAccount.credit(amount); 15 | } 16 | } 17 | } 18 | 19 | public void deadlockFreeTransferMoney(Account fromAccount, Account toAccount, int amount) { 20 | int fromHash = System.identityHashCode(fromAccount); 21 | int toHash = System.identityHashCode(toAccount); 22 | 23 | class transferMoneyHelper { 24 | void transfer(Account fromAccount, Account toAccount, int amount) { 25 | fromAccount.debit(amount); 26 | toAccount.credit(amount); 27 | } 28 | } 29 | 30 | if (fromHash < toHash) { 31 | synchronized (fromAccount) { 32 | synchronized (toAccount) { 33 | new transferMoneyHelper().transfer(fromAccount, toAccount, amount); 34 | } 35 | } 36 | } else if (fromHash < toHash) { 37 | synchronized (toAccount) { 38 | synchronized (fromAccount) { 39 | new transferMoneyHelper().transfer(fromAccount, toAccount, amount); 40 | } 41 | } 42 | } else { 43 | synchronized (tieLock) { 44 | synchronized (fromAccount) { 45 | synchronized (toAccount) { 46 | new transferMoneyHelper().transfer(fromAccount, toAccount, amount); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | static class Account { 54 | int balance; 55 | 56 | int getBalance() { 57 | return balance; 58 | } 59 | 60 | void debit(int toDeduct) { 61 | balance = balance - toDeduct; 62 | } 63 | 64 | void credit(int toCredit) { 65 | balance = balance + toCredit; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/com/vivek/threading/EvenOddPrinterUsingExecutor.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /* 8 | * This is based on producer-consumer problem 9 | */ 10 | public class EvenOddPrinterUsingExecutor { 11 | 12 | public static void main(String[] args) { 13 | ExecutorService es = Executors.newFixedThreadPool(2); 14 | 15 | Mutex mutex = new Mutex(); 16 | OddPrinter op = new OddPrinter(mutex); 17 | EvenPrinter ep = new EvenPrinter(mutex); 18 | 19 | Mutex.oddFlag = true; 20 | 21 | es.execute(op); 22 | es.execute(ep); 23 | 24 | if (null != es) { 25 | es.shutdown(); 26 | try { 27 | es.awaitTermination(1, TimeUnit.MINUTES); 28 | } catch (InterruptedException e) { 29 | Thread.currentThread().interrupted(); 30 | } 31 | } 32 | } 33 | 34 | 35 | static class Mutex { 36 | public static boolean oddFlag; 37 | } 38 | 39 | static class OddPrinter implements Runnable { 40 | private Mutex mutex; 41 | 42 | public OddPrinter(Mutex mutex) { 43 | this.mutex = mutex; 44 | } 45 | 46 | public void run() { 47 | for (int i = 1; i < 100; i+=2) { 48 | synchronized(mutex) { 49 | while (!(mutex.oddFlag)){ 50 | try { 51 | mutex.wait(); 52 | } catch (InterruptedException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | if (mutex.oddFlag) { 58 | System.out.println("OddPrinter = " + i); 59 | mutex.oddFlag = false; 60 | mutex.notify(); 61 | } 62 | 63 | } 64 | } 65 | } 66 | } 67 | 68 | static class EvenPrinter implements Runnable { 69 | private Mutex mutex; 70 | 71 | public EvenPrinter(Mutex mutex) { 72 | this.mutex = mutex; 73 | } 74 | 75 | public void run() { 76 | for (int i = 2; i <= 100; i+=2) { 77 | synchronized(mutex) { 78 | while (mutex.oddFlag) { 79 | try { 80 | mutex.wait(); 81 | } catch (InterruptedException e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | if (!mutex.oddFlag) { 87 | System.out.println("EvenPrinter = " + i); 88 | mutex.oddFlag = true; 89 | mutex.notify(); 90 | } 91 | } 92 | } 93 | 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/CountDownLatchExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class CountDownLatchExample { 9 | 10 | /* 11 | * CountDownLatch is a concurrency construct that allows one or more threads to wait for a given set of operations to complete. 12 | * 13 | * A CountDownLatch is initialized with a given count. This count is decremented by calls to the countDown() method. 14 | * Threads waiting for this count to reach zero can call one of the await() methods. 15 | * Calling await() blocks the thread until the count reaches zero. 16 | * 17 | */ 18 | public static void main(String[] args) { 19 | CountDownLatch latch = new CountDownLatch(3); 20 | Waiter waiter = new Waiter(latch); 21 | Decrementer decrementer = new Decrementer(latch); 22 | 23 | ExecutorService es = Executors.newFixedThreadPool(2); 24 | es.execute(waiter); 25 | es.execute(decrementer); 26 | 27 | if (es != null) { 28 | es.shutdown(); 29 | try { 30 | es.awaitTermination(5000, TimeUnit.SECONDS); 31 | } 32 | catch (InterruptedException e) { 33 | Thread.currentThread().interrupted(); 34 | } 35 | } 36 | 37 | } 38 | 39 | static class Waiter implements Runnable { 40 | private CountDownLatch latch; 41 | 42 | public Waiter(CountDownLatch latch) { 43 | this.latch = latch; 44 | } 45 | 46 | public void run() { 47 | try { 48 | latch.await(); 49 | } catch (InterruptedException e) { 50 | 51 | } 52 | System.out.println("Waiter released!!"); 53 | } 54 | } 55 | 56 | static class Decrementer implements Runnable { 57 | private CountDownLatch latch; 58 | 59 | public Decrementer(CountDownLatch latch) { 60 | this.latch = latch; 61 | } 62 | 63 | public void run() { 64 | try { 65 | latch.countDown(); 66 | System.out.println("Decrementing CountDownLatch"); 67 | Thread.sleep(2000); 68 | latch.countDown(); 69 | System.out.println("Decrementing CountDownLatch"); 70 | Thread.sleep(1000); 71 | latch.countDown(); 72 | System.out.println("Decrementing CountDownLatch"); 73 | Thread.sleep(2000); 74 | } catch (InterruptedException e) { 75 | 76 | } 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/com/vivek/threading/KeepThreadRunning.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * After starting a thread, how could we keep it running until explicitly killed 7 | */ 8 | public class KeepThreadRunning { 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | Worker worker = new Worker(); 12 | worker.start(); 13 | TimeUnit.MILLISECONDS.sleep(25000); 14 | worker.stopThread(); 15 | } 16 | 17 | /** 18 | * Here the process stops when the doWork() method returns false. It is also good style to allow your thread to be interrupted, 19 | * especially if it needs to run for a long time. 20 | * Note you cannot restart threads, once the run method has returned, the thread is reclaimed by the system. 21 | * If you need more control over your threads you could create separate Worker and ThreadManager classes. 22 | * 23 | * To let the ThreadManager terminate the Worker, create a volatile boolean field in your Worker which is checked periodically: 24 | * The Worker ends when interrupted or when the work is completed. Also the ThreadManager can request the Worker to stop by invoking the stopRunning() method. 25 | * 26 | * If your thread runs out of work it could also call the wait() method on the ThreadManager. 27 | * This pauses the thread until it is notified that there is new work to do. The ThreadManager should call notify() or notifyAll() when new work arrives 28 | * 29 | * With this approach you can keep the Worker simple and only concerned with doing the work. 30 | * The ThreadManager determines the number of threads and makes work available to them but does not need to know details of the actual work. 31 | */ 32 | private static class Worker extends Thread { 33 | 34 | private volatile boolean running; 35 | 36 | @Override 37 | public void run() { 38 | running = true; 39 | while (running) { 40 | doWork(); 41 | if (Thread.interrupted()) { 42 | return; 43 | } 44 | } 45 | } 46 | 47 | public void stopThread() { 48 | running = false; 49 | } 50 | 51 | } 52 | 53 | static void doWork() { 54 | try { 55 | System.out.println("Task Started"); 56 | Thread.sleep(10000); 57 | System.out.println("Task Finished"); 58 | } catch (InterruptedException ignored) { } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/com/vivek/threading/RunThreadsInOrderUsingSemaphore.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | /** 6 | * Created by VJaiswal on 14/05/18. 7 | */ 8 | public class RunThreadsInOrderUsingSemaphore { 9 | 10 | private static Semaphore semA = new Semaphore(0); 11 | private static Semaphore semB = new Semaphore(0); 12 | private static Semaphore semC = new Semaphore(1); 13 | 14 | static class Foo { 15 | 16 | /* If funcA is called, a new thread will be created and 17 | the corresponding action will be executed. */ 18 | void funcA() { 19 | Runnable action = () -> { 20 | try { 21 | semC.acquire(1); 22 | Thread.sleep(4000); 23 | } catch (InterruptedException ignored) {} 24 | System.out.println("Running method funcA"); 25 | semA.release(1); 26 | }; 27 | 28 | execute(action); 29 | } 30 | 31 | /* If funcB is called, a new thread will be created and 32 | the corresponding action will be executed. */ 33 | void funcB() throws InterruptedException { 34 | 35 | Runnable action = () -> { 36 | try { 37 | semA.acquire(1); 38 | 39 | Thread.sleep(2000); 40 | } catch (InterruptedException ignored) {} 41 | System.out.println("Running method funcB"); 42 | semB.release(1); 43 | }; 44 | 45 | execute(action); 46 | } 47 | 48 | /* If funcC is called, a new thread will be created and 49 | the corresponding action will be executed. */ 50 | void funcC() throws InterruptedException { 51 | 52 | Runnable action = () -> { 53 | try { 54 | semB.acquire(1); 55 | } catch (InterruptedException ignored) {} 56 | System.out.println("Running method funcC"); 57 | semC.release(1); 58 | }; 59 | 60 | execute(action); 61 | } 62 | 63 | private void execute(Runnable action) { 64 | Thread thread = new Thread(action); 65 | thread.start(); 66 | } 67 | 68 | } 69 | 70 | public static void main(String[] args) throws Exception { 71 | Foo foo = new Foo(); 72 | 73 | foo.funcA(); 74 | foo.funcB(); 75 | foo.funcC(); 76 | 77 | foo.funcA(); 78 | foo.funcB(); 79 | foo.funcC(); 80 | 81 | foo.funcA(); 82 | foo.funcB(); 83 | foo.funcC(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/com/vivek/threading/TumblingWindowCounter.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.temporal.ChronoUnit; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | /** 11 | * Tumbling window counter for events using a scheduled executor service to reset the counter at the start of a new hour 12 | * 13 | * Dynamic Delay Calculation: 14 | * The delay for the next reset is dynamically calculated to ensure it aligns with the next hour boundary. 15 | */ 16 | public class TumblingWindowCounter { 17 | 18 | private final AtomicLong eventCounter = new AtomicLong(0); 19 | private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); 20 | 21 | public TumblingWindowCounter() { 22 | scheduleHourlyReset(); 23 | } 24 | 25 | // Increment the counter for each event 26 | public void onEvent() { 27 | eventCounter.incrementAndGet(); 28 | } 29 | 30 | // Get the current count 31 | public long getCount() { 32 | return eventCounter.get(); 33 | } 34 | 35 | // Schedule a reset at the start of every hour 36 | private void scheduleHourlyReset() { 37 | long delay = calculateDelayUntilNextHour(); 38 | 39 | scheduler.scheduleAtFixedRate(() -> { 40 | System.out.println("Hour ended. Total count: " + getCount()); 41 | eventCounter.set(0); // Reset the counter 42 | }, delay, TimeUnit.HOURS.toMillis(1), TimeUnit.MILLISECONDS); 43 | } 44 | 45 | // Calculate the delay until the next hour 46 | private long calculateDelayUntilNextHour() { 47 | LocalDateTime now = LocalDateTime.now(); 48 | LocalDateTime nextHour = now.truncatedTo(ChronoUnit.HOURS).plusHours(1); 49 | return ChronoUnit.MILLIS.between(now, nextHour); 50 | } 51 | 52 | // Shutdown the scheduler gracefully 53 | public void shutdown() { 54 | scheduler.shutdown(); 55 | try { 56 | if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) { 57 | scheduler.shutdownNow(); 58 | } 59 | } catch (InterruptedException e) { 60 | scheduler.shutdownNow(); 61 | } 62 | } 63 | 64 | public static void main(String[] args) { 65 | TumblingWindowCounter counter = new TumblingWindowCounter(); 66 | 67 | // Simulate events 68 | for (int i = 0; i < 100; i++) { 69 | counter.onEvent(); 70 | } 71 | 72 | System.out.println("Current count: " + counter.getCount()); 73 | 74 | // Simulate shutdown after 2 hours for demonstration purposes 75 | Executors.newSingleThreadScheduledExecutor().schedule(counter::shutdown, 2, TimeUnit.HOURS); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/com/vivek/threading/CollapsedForwarding.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.*; 4 | 5 | public class CollapsedForwarding { 6 | 7 | // A map to track ongoing requests for each resource 8 | private final ConcurrentHashMap> requestCache = new ConcurrentHashMap<>(); 9 | 10 | /** 11 | * Fetches a resource, collapsing duplicate requests into a single upstream call. 12 | * 13 | * @param resourceId The unique identifier for the resource. 14 | * @return The data for the requested resource. 15 | * @throws ExecutionException If the data fetch fails. 16 | * @throws InterruptedException If the thread is interrupted. 17 | */ 18 | public byte[] fetchResource(String resourceId) throws ExecutionException, InterruptedException { 19 | // Get or create a CompletableFuture for the resource 20 | CompletableFuture future = requestCache.computeIfAbsent(resourceId, key -> { 21 | // The first thread initiates the data fetch 22 | return CompletableFuture.supplyAsync(() -> { 23 | try { 24 | // Simulate fetching the resource (e.g., from a database or remote server) 25 | return fetchDataFromSource(key); 26 | } finally { 27 | // Clean up the map entry after processing 28 | requestCache.remove(key); 29 | } 30 | }); 31 | }); 32 | 33 | // All threads wait for and return the same result 34 | return future.get(); 35 | } 36 | 37 | /** 38 | * Simulates fetching data from an external source. 39 | * 40 | * @param resourceId The unique identifier for the resource. 41 | * @return The fetched data as a byte array. 42 | */ 43 | private byte[] fetchDataFromSource(String resourceId) { 44 | System.out.println("Fetching data for resource: " + resourceId); 45 | // Simulate network or I/O delay 46 | try { 47 | Thread.sleep(1000); 48 | } catch (InterruptedException e) { 49 | Thread.currentThread().interrupt(); 50 | } 51 | return ("Data for " + resourceId).getBytes(); 52 | } 53 | 54 | public static void main(String[] args) { 55 | CollapsedForwarding collapsedForwarding = new CollapsedForwarding(); 56 | 57 | ExecutorService executor = Executors.newFixedThreadPool(10); 58 | String resourceId = "resource1"; 59 | 60 | // Simulate multiple concurrent requests for the same resource 61 | for (int i = 0; i < 5; i++) { 62 | executor.submit(() -> { 63 | try { 64 | byte[] data = collapsedForwarding.fetchResource(resourceId); 65 | System.out.println("Thread " + Thread.currentThread().getName() + " received: " + new String(data)); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | }); 70 | } 71 | 72 | executor.shutdown(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/CyclicBarrierExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.BrokenBarrierException; 4 | import java.util.concurrent.CyclicBarrier; 5 | 6 | public class CyclicBarrierExample implements Runnable { 7 | 8 | /* 9 | * CyclicBarrier class is a synchronization mechanism that can synchronize threads progressing through some algorithm. 10 | * In other words, it is a barrier that all threads must wait at, until all threads reach it, before any of the threads can continue. 11 | * 12 | * The threads wait for each other by calling the await() method on the CyclicBarrier. 13 | * Once N threads are waiting at the CyclicBarrier, all threads are released and can continue running. 14 | * 15 | * When you create a CyclicBarrier you specify how many threads are to wait at it, before releasing them. 16 | * CyclicBarrier supports a barrier action, which is a Runnable that is executed once the last thread arrives. 17 | * You pass the Runnable barrier action to the CyclicBarrier in its constructor, 18 | * 19 | * Runnable barrierAction = ... ; 20 | * CyclicBarrier barrier = new CyclicBarrier(2, barrierAction); 21 | * 22 | * http://tutorials.jenkov.com/java-util-concurrent/cyclicbarrier.html 23 | */ 24 | 25 | CyclicBarrier barrier1 = null; 26 | CyclicBarrier barrier2 = null; 27 | 28 | public CyclicBarrierExample(CyclicBarrier barrier1, CyclicBarrier barrier2) { 29 | 30 | this.barrier1 = barrier1; 31 | this.barrier2 = barrier2; 32 | } 33 | 34 | public void run() { 35 | try { 36 | Thread.sleep(1000); 37 | System.out.println(Thread.currentThread().getName() + 38 | " waiting at barrier 1"); 39 | this.barrier1.await(); 40 | 41 | Thread.sleep(1000); 42 | System.out.println(Thread.currentThread().getName() + 43 | " waiting at barrier 2"); 44 | this.barrier2.await(); 45 | 46 | System.out.println(Thread.currentThread().getName() + 47 | " done!"); 48 | 49 | } catch (InterruptedException e) { 50 | e.printStackTrace(); 51 | } catch (BrokenBarrierException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | 56 | public static void main(String[] args) { 57 | Runnable barrier1Action = new Runnable() { 58 | public void run() { 59 | System.out.println("BarrierAction 1 executed "); 60 | } 61 | }; 62 | Runnable barrier2Action = new Runnable() { 63 | public void run() { 64 | System.out.println("BarrierAction 2 executed "); 65 | } 66 | }; 67 | 68 | CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action); 69 | CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action); 70 | 71 | CyclicBarrierExample barrierRunnable1 = 72 | new CyclicBarrierExample(barrier1, barrier2); 73 | 74 | CyclicBarrierExample barrierRunnable2 = 75 | new CyclicBarrierExample(barrier1, barrier2); 76 | 77 | new Thread(barrierRunnable1).start(); 78 | new Thread(barrierRunnable2).start(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/com/vivek/threading/H2O.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.BrokenBarrierException; 4 | import java.util.concurrent.CyclicBarrier; 5 | import java.util.concurrent.Semaphore; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | /** 9 | * 1117. Building H2O 10 | * 11 | * There are two kinds of threads: oxygen and hydrogen. Your goal is to group these threads to form water molecules. 12 | * 13 | * There is a barrier where each thread has to wait until a complete molecule can be formed. 14 | * Hydrogen and oxygen threads will be given releaseHydrogen and releaseOxygen methods respectively, 15 | * which will allow them to pass the barrier. These threads should pass the barrier in groups of three, 16 | * and they must immediately bond with each other to form a water molecule. 17 | * You must guarantee that all the threads from one molecule bond before any other threads from the next molecule do. 18 | * 19 | * In other words: 20 | * 21 | * 1. If an oxygen thread arrives at the barrier when no hydrogen threads are present, it must wait for two hydrogen threads. 22 | * 2. If a hydrogen thread arrives at the barrier when no other threads are present, it must wait for an oxygen thread and another hydrogen thread. 23 | * 24 | * We do not have to worry about matching the threads up explicitly; 25 | * the threads do not necessarily know which other threads they are paired up with. 26 | * The key is that threads pass the barriers in complete sets; thus, 27 | * if we examine the sequence of threads that bind and divide them into groups of three, 28 | * each group should contain one oxygen and two hydrogen threads. 29 | * 30 | * Write synchronization code for oxygen and hydrogen molecules that enforces these constraints. 31 | * 32 | * Example 1: 33 | * 34 | * Input: water = "HOH" 35 | * Output: "HHO" 36 | * Explanation: "HOH" and "OHH" are also valid answers. 37 | * 38 | * Example 2: 39 | * 40 | * Input: water = "OOHHHH" 41 | * Output: "HHOHHO" 42 | * Explanation: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" and "OHHOHH" are also valid answers. 43 | * 44 | * Constraints: 45 | * 46 | * 3 * n == water.length 47 | * 1 <= n <= 20 48 | * water[i] is either 'H' or 'O'. 49 | * There will be exactly 2 * n 'H' in water. 50 | * There will be exactly n 'O' in water. 51 | * 52 | * Reference: 53 | * https://leetcode.com/problems/building-h2o/description/ 54 | * 55 | */ 56 | public class H2O { 57 | 58 | private final Semaphore lockH; 59 | private final Semaphore lockO; 60 | private final AtomicInteger hydrogenCount; 61 | 62 | public H2O() { 63 | this.hydrogenCount = new AtomicInteger(); 64 | this.lockH = new Semaphore(2); 65 | this.lockO = new Semaphore(1); 66 | } 67 | 68 | public void hydrogen(Runnable releaseHydrogen) throws InterruptedException { 69 | lockH.acquire(); 70 | releaseHydrogen.run(); 71 | 72 | if (hydrogenCount.incrementAndGet() == 2) { 73 | hydrogenCount.set(0); 74 | lockO.release(); 75 | } 76 | } 77 | 78 | public void oxygen(Runnable releaseOxygen) throws InterruptedException { 79 | lockO.acquire(); 80 | releaseOxygen.run(); 81 | lockH.release(2); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/com/vivek/threading/CustomThreadPoolExecutor.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public class CustomThreadPoolExecutor { 8 | 9 | private final Worker[] pool; 10 | private final BlockingQueue queue; 11 | private boolean isStopped; 12 | 13 | public CustomThreadPoolExecutor(int numThreads, int queueSize) { 14 | this.pool = new Worker[numThreads]; 15 | this.queue = new LinkedBlockingQueue<>(queueSize); 16 | int i = 0; 17 | for (int k = 0; k < numThreads; k++) { 18 | pool[k] = new Worker("custom-thread-pool-executor-" + ++i, queue); 19 | } 20 | 21 | for (Worker workerThread : pool) { 22 | workerThread.start(); 23 | } 24 | } 25 | 26 | public synchronized void submit(Runnable task) { 27 | if (isStopped) 28 | throw new IllegalStateException("ThreadPool is stopped"); 29 | try { 30 | queue.put(task); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | public synchronized void stop() { 37 | isStopped = true; 38 | for (Worker workerThread : pool) { 39 | workerThread.doStop(); 40 | } 41 | } 42 | 43 | public synchronized void waitUntilAllTasksFinished() { 44 | while (queue.size() > 0) { 45 | try { 46 | TimeUnit.MILLISECONDS.sleep(100); 47 | } catch (InterruptedException ex) { 48 | ex.printStackTrace(); 49 | } 50 | } 51 | } 52 | 53 | private static class Worker extends Thread { 54 | 55 | private final BlockingQueue queue; 56 | private boolean isStopped; 57 | private Thread thread; 58 | 59 | public Worker(String threadName, BlockingQueue queue) { 60 | super(threadName); 61 | this.queue = queue; 62 | } 63 | 64 | @Override 65 | public void run() { 66 | thread = Thread.currentThread(); 67 | while (!isStopped) { 68 | try { 69 | queue.take().run(); 70 | } catch (InterruptedException ignored) { } 71 | } 72 | } 73 | 74 | public synchronized void doStop() { 75 | isStopped = true; 76 | thread.interrupt(); // break pool thread out of dequeue() call 77 | } 78 | 79 | public synchronized boolean isStopped() { 80 | return isStopped; 81 | } 82 | 83 | } 84 | 85 | public static void main(String[] args) { 86 | CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor(10, 100); 87 | 88 | for (int i = 1; i <= 200; i++) { 89 | int taskNumber = i; 90 | executor.submit(() -> { 91 | String message = "[" + Thread.currentThread().getName() + "] : Task " + taskNumber; 92 | System.out.println(message); 93 | }); 94 | } 95 | 96 | executor.waitUntilAllTasksFinished(); 97 | executor.stop(); 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/com/vivek/threading/PrintFizzBuzz.java: -------------------------------------------------------------------------------- 1 | package com.vivek.threading; 2 | 3 | import java.util.concurrent.Semaphore; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | import java.util.function.IntConsumer; 6 | 7 | public class PrintFizzBuzz { 8 | 9 | private int n; 10 | private Semaphore lock; 11 | private AtomicInteger counter; 12 | 13 | public PrintFizzBuzz(int n) { 14 | this.n = n; 15 | this.lock = new Semaphore(1); 16 | this.counter = new AtomicInteger(1); 17 | } 18 | 19 | // printFizz.run() outputs "fizz". 20 | public void fizz(Runnable printFizz) throws InterruptedException { 21 | int step = n/3 - n/15; 22 | int i = 0; 23 | while (i < step) { 24 | lock.acquire(); 25 | if (counter.get() % 3 == 0 && counter.get() % 15 != 0) { 26 | printFizz.run(); 27 | counter.incrementAndGet(); 28 | i++; 29 | } 30 | lock.release(); 31 | } 32 | } 33 | 34 | // printBuzz.run() outputs "buzz". 35 | public void buzz(Runnable printBuzz) throws InterruptedException { 36 | int step = n/5 - n/15; 37 | int i = 0; 38 | while (i < step) { 39 | lock.acquire(); 40 | if (counter.get() % 5 == 0 && counter.get() % 15 != 0) { 41 | printBuzz.run(); 42 | counter.incrementAndGet(); 43 | i++; 44 | } 45 | lock.release(); 46 | } 47 | } 48 | 49 | // printFizzBuzz.run() outputs "fizzbuzz". 50 | public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException { 51 | int step = n/15; 52 | int i = 0; 53 | while (i < step) { 54 | lock.acquire(); 55 | if (counter.get() % 15 == 0) { 56 | printFizzBuzz.run(); 57 | counter.incrementAndGet(); 58 | i++; 59 | } 60 | lock.release(); 61 | } 62 | } 63 | 64 | // printNumber.accept(x) outputs "x", where x is an integer. 65 | public void number(IntConsumer printNumber) throws InterruptedException { 66 | int step = n - n/3 - n/5 + n/15; 67 | int i = 0; 68 | while (i < step) { 69 | lock.acquire(); 70 | if (counter.get() % 3 != 0 && counter.get() % 5 != 0) { 71 | printNumber.accept(counter.get()); 72 | counter.incrementAndGet(); 73 | i++; 74 | } 75 | lock.release(); 76 | } 77 | } 78 | 79 | public static void main(String[] args) { 80 | PrintFizzBuzz fizzBuzz = new PrintFizzBuzz(15); 81 | 82 | Runnable printFizz = () -> System.out.println("fizz"); 83 | Runnable printBuzz = () -> System.out.println("buzz"); 84 | Runnable printFizzBuzz = () -> System.out.println("fizzbuzz"); 85 | IntConsumer printNumber = number -> System.out.println(number); 86 | 87 | Thread threadA = new Thread(() -> { 88 | try { 89 | fizzBuzz.fizz(printFizz); 90 | } catch (InterruptedException e) { 91 | e.printStackTrace(); 92 | } 93 | }); 94 | Thread threadB = new Thread(() -> { 95 | try { 96 | fizzBuzz.buzz(printBuzz); 97 | } catch (InterruptedException e) { 98 | e.printStackTrace(); 99 | } 100 | }); 101 | Thread threadC = new Thread(() -> { 102 | try { 103 | fizzBuzz.fizzbuzz(printFizzBuzz); 104 | } catch (InterruptedException e) { 105 | e.printStackTrace(); 106 | } 107 | }); 108 | Thread threadD = new Thread(() -> { 109 | try { 110 | fizzBuzz.number(printNumber); 111 | } catch (InterruptedException e) { 112 | e.printStackTrace(); 113 | } 114 | }); 115 | 116 | threadA.start(); 117 | threadB.start(); 118 | threadC.start(); 119 | threadD.start(); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ExecutorServiceExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.HashSet; 4 | import java.util.List; 5 | import java.util.Set; 6 | import java.util.concurrent.*; 7 | 8 | public class ExecutorServiceExample { 9 | 10 | /* 11 | * ExecutorService interface represents an asynchronous execution mechanism which is capable of executing tasks in the background. 12 | */ 13 | public static void main(String[] args) { 14 | ExecutorService executorService = Executors.newFixedThreadPool(10); 15 | 16 | executorService.execute(new Runnable() { 17 | public void run() { 18 | System.out.println("Asynchronous task"); 19 | } 20 | }); 21 | 22 | executorService.shutdown(); 23 | 24 | 25 | // Creating an ExecutorService 26 | ExecutorService executorService1 = Executors.newSingleThreadExecutor(); 27 | ExecutorService executorService2 = Executors.newFixedThreadPool(10); 28 | ExecutorService executorService3 = Executors.newScheduledThreadPool(10); 29 | 30 | // There are a few different ways to delegate tasks for execution to an ExecutorService: 31 | // execute(Runnable) 32 | // submit(Runnable) 33 | // submit(Callable) 34 | // invokeAny(...) 35 | // invokeAll(...) 36 | 37 | /** 38 | * execute(Runnable) 39 | * 40 | * There is no way of obtaining the result of the executed Runnable, if necessary. 41 | */ 42 | executorService = Executors.newSingleThreadExecutor(); 43 | 44 | executorService.execute(new Runnable() { 45 | public void run() { 46 | System.out.println("Asynchronous task"); 47 | } 48 | }); 49 | 50 | executorService.shutdown(); 51 | 52 | /** 53 | * submit(Runnable) 54 | */ 55 | Future future = executorService.submit(new Runnable() { 56 | public void run() { 57 | System.out.println("Asynchronous task"); 58 | } 59 | }); 60 | 61 | try { 62 | future.get(); //returns null if the task has finished correctly. 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } catch (ExecutionException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | /** 70 | * submit(Callable) 71 | */ 72 | Future future1 = executorService.submit(new Callable(){ 73 | public Object call() throws Exception { 74 | System.out.println("Asynchronous Callable"); 75 | return "Callable Result"; 76 | } 77 | }); 78 | 79 | try { 80 | System.out.println("future.get() = " + future1.get()); 81 | } catch (InterruptedException | ExecutionException e) { 82 | e.printStackTrace(); 83 | } 84 | 85 | /** 86 | * invokeAny() 87 | * 88 | * The invokeAny() method takes a collection of Callable objects, or subinterfaces of Callable. 89 | * Invoking this method does not return a Future, but returns the result of one of the Callable objects. 90 | * You have no guarantee about which of the Callable's results you get. Just one of the ones that finish. 91 | * If one of the tasks complete (or throws an exception), the rest of the Callable's are cancelled. 92 | */ 93 | ExecutorService singleExecutor1 = Executors.newSingleThreadExecutor(); 94 | Set> callables = new HashSet>(); 95 | callables.add(new Callable() { 96 | public String call() throws Exception { 97 | return "Task 1"; 98 | } 99 | }); 100 | 101 | callables.add(new Callable() { 102 | public String call() throws Exception { 103 | return "Task 2"; 104 | } 105 | }); 106 | 107 | callables.add(new Callable() { 108 | public String call() throws Exception { 109 | return "Task 3"; 110 | } 111 | }); 112 | 113 | try { 114 | System.out.println(singleExecutor1.invokeAny(callables)); 115 | } catch (InterruptedException | ExecutionException e) { 116 | e.printStackTrace(); 117 | } 118 | 119 | /** 120 | * invokeAll() 121 | * 122 | * The invokeAll() method invokes all of the Callable objects you pass to it in the collection passed as parameter. 123 | * The invokeAll() returns a list of Future objects via which you can obtain the results of the executions of each Callable. 124 | */ 125 | ExecutorService singleExecutor2 = Executors.newSingleThreadExecutor(); 126 | List> futures; 127 | 128 | try { 129 | futures = singleExecutor2.invokeAll(callables); 130 | for(Future future11 : futures){ 131 | System.out.println("future.get = " + future11.get()); 132 | } 133 | } catch (InterruptedException | ExecutionException e) { 134 | e.printStackTrace(); 135 | } 136 | 137 | 138 | // When you are done using the ExecutorService you should shut it down, so the threads do not keep running. 139 | // if your application is started via a main() method and your main thread exits your application, 140 | // the application will keep running if you have an active ExexutorService in your application. 141 | // The active threads inside this ExecutorService prevents the JVM from shutting down. 142 | singleExecutor2.shutdown(); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/ForkJoinPoolExample.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ForkJoinPool; 6 | import java.util.concurrent.RecursiveAction; 7 | import java.util.concurrent.RecursiveTask; 8 | 9 | public class ForkJoinPoolExample { 10 | 11 | /* 12 | * The ForkJoinPool makes it easy for tasks to split their work up into smaller tasks which are then submitted to the ForkJoinPool too. 13 | * Tasks can keep splitting their work into smaller subtasks for as long as it makes to split up the task. 14 | */ 15 | public static void main(String[] args) { 16 | ForkJoinPool forkJoinPool = new ForkJoinPool(4); // parallelism level of 4. The parallelism level indicates how many threads or CPUs you want to work concurrently on tasks passed to the ForkJoinPool. 17 | 18 | /* 19 | * You submit tasks to a ForkJoinPool similarly to how you submit tasks to an ExecutorService. 20 | * You can submit two types of tasks. A task that does not return any result (an "action"), 21 | * and a task which does return a result (a "task"). 22 | * These two types of tasks are represented by the RecursiveAction and RecursiveTask classes. 23 | */ 24 | 25 | /** 26 | * RecursiveAction 27 | * 28 | * A RecursiveAction is a task which does not return any value. It just does some work, e.g. writing data to disk, and then exits. 29 | * A RecursiveAction may still need to break up its work into smaller chunks which can be executed by independent threads or CPUs. 30 | */ 31 | 32 | class MyRecursiveAction extends RecursiveAction { 33 | 34 | private long workLoad = 0; 35 | 36 | public MyRecursiveAction(long workLoad) { 37 | this.workLoad = workLoad; 38 | } 39 | 40 | @Override 41 | protected void compute() { 42 | 43 | //if work is above threshold, break tasks up into smaller tasks 44 | if(this.workLoad > 16) { 45 | System.out.println("Splitting workLoad : " + this.workLoad); 46 | 47 | List subtasks = 48 | new ArrayList(); 49 | 50 | subtasks.addAll(createSubtasks()); 51 | 52 | for(RecursiveAction subtask : subtasks){ 53 | subtask.fork(); 54 | } 55 | 56 | } else { 57 | System.out.println("Doing workLoad myself: " + this.workLoad); 58 | } 59 | } 60 | 61 | private List createSubtasks() { 62 | List subtasks = 63 | new ArrayList(); 64 | 65 | MyRecursiveAction subtask1 = new MyRecursiveAction(this.workLoad / 2); 66 | MyRecursiveAction subtask2 = new MyRecursiveAction(this.workLoad / 2); 67 | 68 | subtasks.add(subtask1); 69 | subtasks.add(subtask2); 70 | 71 | return subtasks; 72 | } 73 | } 74 | 75 | 76 | /** 77 | * RecursiveTask 78 | * 79 | * A RecursiveTask is a task that returns a result. It may split its work up into smaller tasks, 80 | * and merge the result of these smaller tasks into a collective result. The splitting and merging may take place on several levels. 81 | */ 82 | class MyRecursiveTask extends RecursiveTask { 83 | 84 | private long workLoad = 0; 85 | 86 | public MyRecursiveTask(long workLoad) { 87 | this.workLoad = workLoad; 88 | } 89 | 90 | protected Long compute() { 91 | 92 | //if work is above threshold, break tasks up into smaller tasks 93 | if(this.workLoad > 16) { 94 | System.out.println("Splitting workLoad : " + this.workLoad); 95 | 96 | List subtasks = 97 | new ArrayList(); 98 | subtasks.addAll(createSubtasks()); 99 | 100 | for(MyRecursiveTask subtask : subtasks){ 101 | subtask.fork(); 102 | } 103 | 104 | long result = 0; 105 | for(MyRecursiveTask subtask : subtasks) { 106 | result += subtask.join(); 107 | } 108 | return result; 109 | 110 | } else { 111 | System.out.println("Doing workLoad myself: " + this.workLoad); 112 | return workLoad * 3; 113 | } 114 | } 115 | 116 | private List createSubtasks() { 117 | List subtasks = 118 | new ArrayList(); 119 | 120 | MyRecursiveTask subtask1 = new MyRecursiveTask(this.workLoad / 2); 121 | MyRecursiveTask subtask2 = new MyRecursiveTask(this.workLoad / 2); 122 | 123 | subtasks.add(subtask1); 124 | subtasks.add(subtask2); 125 | 126 | return subtasks; 127 | } 128 | } 129 | 130 | 131 | // Schedule a RecursiveTask 132 | MyRecursiveTask myRecursiveTask = new MyRecursiveTask(128); 133 | 134 | long mergedResult = forkJoinPool.invoke(myRecursiveTask); 135 | 136 | System.out.println("mergedResult = " + mergedResult); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/com/vivek/concurrentutil/AtomicUtils.java: -------------------------------------------------------------------------------- 1 | package com.vivek.concurrentutil; 2 | 3 | import java.util.concurrent.atomic.*; 4 | 5 | public class AtomicUtils { 6 | 7 | @SuppressWarnings({ "unused", "rawtypes", "unchecked" }) 8 | public static void main(String[] args) { 9 | /** 10 | * AtomicBoolean 11 | */ 12 | AtomicBoolean bool = new AtomicBoolean(); // default initial value is false 13 | AtomicBoolean bool2 = new AtomicBoolean(true); // initial value is set to true 14 | 15 | boolean value = bool.get(); 16 | bool2.set(false); 17 | 18 | boolean oldValue = bool.getAndSet(true); // returns the AtomicBoolean's current value, and sets a new value for it 19 | 20 | boolean expected = true; 21 | boolean newValue = false; 22 | 23 | boolean wasNewValueSet = bool.compareAndSet(expected, newValue); 24 | 25 | /** 26 | * AtomicInteger 27 | * 28 | * AtomicLong has same methods as AtomicInteger 29 | */ 30 | AtomicInteger atomicInteger = new AtomicInteger(); // initial value 0 31 | AtomicInteger atomicInteger2 = new AtomicInteger(123); 32 | 33 | int theValue = atomicInteger.get(); 34 | atomicInteger.set(234); 35 | 36 | int expectedValue = 123; 37 | int newValue2 = 234; 38 | atomicInteger.compareAndSet(expectedValue, newValue2); 39 | 40 | System.out.println(atomicInteger.getAndAdd(10)); 41 | System.out.println(atomicInteger.addAndGet(10)); 42 | 43 | /** 44 | * AtomicReference 45 | */ 46 | AtomicReference atomicRef = new AtomicReference(); 47 | 48 | String initialReference = "the initially referenced string"; 49 | AtomicReference atomicReference = new AtomicReference(initialReference); 50 | 51 | AtomicReference atomicStringReference = 52 | new AtomicReference(initialReference); 53 | 54 | String reference = (String) atomicReference.get(); 55 | String reference2 = atomicStringReference.get(); 56 | 57 | atomicReference.set("New object referenced"); 58 | 59 | /** 60 | * AtomicStampedReference 61 | */ 62 | /* 63 | The AtomicStampedReference is different from the AtomicReference in that the AtomicStampedReference keeps both an object reference and a stamp internally. The reference and stamp can be swapped using a single atomic compare-and-swap operation, via the compareAndSet() method. 64 | The AtomicStampedReference is designed to be able to solve the A-B-A problem which is not possible to solve with an AtomicReference alone. 65 | 66 | The AtomicStampedReference is designed to solve the A-B-A problem. The A-B-A problem is when a reference is changed from pointing to A, then to B and then back to A. 67 | 68 | When using compare-and-swap operations to change a reference atomically, and making sure that only one thread can change the reference from an old reference to a new, detecting the A-B-A situation is impossible. 69 | 70 | Thread 1 can copy the reference and stamp out of the AtomicStampedReference atomically using get(). If another thread changes the reference from A to B and then back to A, then the stamp will have changed 71 | */ 72 | 73 | Object initialRef = null; 74 | int initialStamp = 0; 75 | 76 | AtomicStampedReference atomicStampedReference = 77 | new AtomicStampedReference(initialRef, initialStamp); 78 | 79 | String initialRef1 = null; 80 | int initialStamp1 = 0; 81 | 82 | AtomicStampedReference atomicStampedStringReference = 83 | new AtomicStampedReference( 84 | initialRef1, initialStamp1); 85 | 86 | String reference1 = (String) atomicStampedReference.getReference(); 87 | int stamp = atomicStampedReference.getStamp(); 88 | 89 | // You can obtain both reference and stamp from an AtomicStampedReference in a single, atomic operation using the get() method. 90 | // The get() method returns the reference as return value from the method. 91 | // The stamp is inserted into an int[] array that is passed as parameter to the get() method. 92 | int[] stampHolder = new int[1]; 93 | Object ref = atomicStampedReference.get(stampHolder); 94 | 95 | String newRef = "New object referenced"; 96 | int newStamp = 1; 97 | 98 | atomicStampedReference.set(newRef, newStamp); 99 | 100 | 101 | boolean exchanged = atomicStampedStringReference 102 | .compareAndSet(initialRef1, newRef, initialStamp, newStamp); 103 | 104 | /** 105 | * AtomicIntegerArray 106 | * 107 | * AtomicLongArray & AtomicReferenceArray are same as AtomicIntegerArray 108 | */ 109 | AtomicIntegerArray array = new AtomicIntegerArray(10); // 10 being the capacity 110 | 111 | int[] ints = new int[10]; 112 | ints[5] = 123; 113 | AtomicIntegerArray array1 = new AtomicIntegerArray(ints); // ints the integer array as input 114 | 115 | int value1 = array.get(5); 116 | array.set(5, 999); 117 | boolean swapped = array.compareAndSet(5, 999, 123); 118 | 119 | int newValue1 = array.addAndGet(5, 3); 120 | int oldValue1 = array.getAndAdd(5, 3); 121 | 122 | int newValue4 = array.incrementAndGet(5); 123 | int oldValue2 = array.getAndIncrement(5); 124 | 125 | int newValue3 = array.decrementAndGet(5); 126 | int oldValue3 = array.getAndDecrement(5); 127 | 128 | 129 | } 130 | 131 | } 132 | --------------------------------------------------------------------------------