Requirement

Recommended

Reuse worker threads

ExecutorService

Delayed result

Future

Async pipelines

CompletableFuture

Massive I/O concurrency

Virtual Threads

Per-thread context

ThreadLocal

Shared counter

AtomicInteger / LongAdder

Shared variable visibility

volatile

Critical section

synchronized / ReentrantLock

Read-heavy data

ReadWriteLock / StampedLock

Parallel CPU tasks

ForkJoinPool

Large collection processing

Parallel Streams

Wait for multiple tasks

CountDownLatch

Synchronize phases

CyclicBarrier

Limit concurrent access

Semaphore

 

ArrayList vs Vector

Feature

ArrayList

Vector

Introduced

Java 1.2

Java 1.0

Thread Safe

No

Yes

Synchronization

None

Every method synchronized

Performance

Faster

Slower

Growth

50% increase

Doubles by default (or configurable)

Legacy

No

Yes

Iterator

Fail-fast

Iterator is fail-fast; Enumeration is not fail-fast

Preferred

Yes

Rarely

 

Time Complexity

Operation

ArrayList

Vector

get()

O(1)

O(1)

set()

O(1)

O(1)

add(end)

O(1) amortized

O(1) amortized

add(index)

O(n)

O(n)

remove

O(n)

O(n)

contains

O(n)

O(n)

 

  Single-threaded or externally synchronized code: ArrayList

  Read-heavy concurrent workloads: CopyOnWriteArrayList

  General concurrent applications: Choose an appropriate collection from java.util.concurrent

  Avoid Vector unless you're maintaining legacy code.

 

 

Thread → Worker

Multithreading → Multiple workers

     Batch processing. Multiple threads share huge workload

Concurrency → Workers taking turns efficiently

           Only one server in the hotel serving for 4 tables efficiently

           Context switching heavily in case of single processor

Parallelism → Workers working at the same time
     4 servers serving 4 tables. 1 server per table
     example : 8 core cpu

Thread-safe → Workers don't corrupt shared data

     Banking transactions – withdrawal –

only one thread is allowed to withdraw and update the balance, not multiple threads in parallel

 

Comparison

Feature

Concurrency

Parallelism

CPU cores

1 or more

Usually multiple

Executes simultaneously

Not necessarily

Yes

Context switching

Yes

Minimal

Goal

Better responsiveness

Faster execution

Example

Web server

Matrix multiplication

 

 

5. Thread Safety

 

balance = 1000

Two threads

Thread A

withdraw(100)

Thread B

withdraw(200)

 

 

Without synchronization

Both read

1000

A writes

900

B writes

800

Final balance

800

 

Correct answer should be

700

This is called a race condition.

 

Thread Safe Example

public synchronized void withdraw(int amount) {

    balance -= amount;

}

// ReentrantLock is more flexible than synchronized

 

Now

Thread A

LOCK

withdraw

UNLOCK

Thread B

LOCK

withdraw

UNLOCK

Result

700

Correct.

 

 

In multithreading

Prefer ConcurrentHashMap instead of HashMap

CopyOnWriteArrayList instead of ArrayList

 

 

├── Thread

├── Runnable

├── Callable

├── Executor

├── ExecutorService

     ├── FixedThreadPool

     ├── CachedThreadPool

     ├── SingleThreadExecutor

     ├── ScheduledExecutorService

     └── WorkStealingPool

├── Future

├── CompletableFuture

├── ForkJoinPool

├── Parallel Streams

├── Virtual Threads (Java 21+)

├── synchronized

├── volatile

├── Lock

├── ReadWriteLock

├── StampedLock

├── AtomicInteger

├── LongAdder

├── ConcurrentHashMap

├── ThreadLocal

├── Semaphore

├── CountDownLatch

├── CyclicBarrier

├── Phaser

└── BlockingQueue

 

Executors.newCachedThreadPool()

Danger. Can create thousands of threads.

Good for Short-lived tasks.

 

Executors.newSingleThreadExecutor()

Useful for

 

schedule()

scheduleAtFixedRate()

scheduleWithFixedDelay()

Run every 10 seconds

Useful for

 

ForkJoinPool

 

Idle threads steal work from busy threads.

Excellent for

 

Future

Represents a result that will be available later.

 

future.get()

future.cancel()

future.isDone()

future.isCancelled()

 

Problem

future.get()

Blocks the current thread.

 

 

3. CompletableFuture

Modern replacement for Future.

Supports

 

supplyAsync()

runAsync()

thenApply()

thenCompose()

thenCombine()

exceptionally()

allOf()

anyOf()

 

 

4. volatile

 

Without volatile

Each thread may have its own cached copy.

Thread B might never see updates made by Thread A.

 

With volatile

volatile int count

Every read goes to main memory.

Every write updates main memory immediately.

Guarantees

·        Visibility

·        Memory ordering

It does not guarantee atomicity.

count++

is still not thread-safe because it consists of:

1.  Read

2.  Increment

3.  Write

Use AtomicInteger instead.

 

volatile vs synchronized

 

volatile

synchronized

Visibility

Visibility + Mutual Exclusion

No locking

Locking

Faster

Slower

No atomicity

Atomic operations

Single variable

Multiple statements

 

volatile guarantees visibility, but AtomicInteger guarantees visibility and atomicity.

 

When to Use volatile

Use it for state flags or configuration values that are written by one thread and read by many threads.

Examples

volatile boolean shutdown;

volatile boolean running;

volatile Configuration config;

You are not performing compound updates like increment or decrement.

 

When to Use AtomicInteger

Use it whenever multiple threads modify a shared numeric value.

Examples

AtomicInteger counter;

AtomicLong requestCount;

AtomicReference<Customer>;

 

volatile only guarantees that every thread sees the latest value. It does not make compound operations such as count++, balance -= amount, or if (count > 0) count-- atomic.

 

Can I replace every volatile with an Atomic class?

No.

For simple state flags (running, shutdown, initialized) or references where you only need visibility, volatile is simpler, lighter, and more readable.

Otherwise it would be overkill