Java Threads and Concurrency
A thread is a path of execution. A Java program starts with one thread (main). With more threads, a program can do many jobs at the same time, like downloading a file while the screen stays active.
Create a thread
public class Main {
public static void main(String[] args) throws InterruptedException {
Runnable job = () -> System.out.println("Hello from " + Thread.currentThread().getName());
Thread t1 = new Thread(job, "worker-1");
Thread t2 = new Thread(job, "worker-2");
t1.start();
t1.join(); // wait until t1 finishes
t2.start();
t2.join();
System.out.println("Main ends");
}
}
Hello from worker-1
Hello from worker-2
Main ends
Call start() to run in a new thread. If you call run() directly, the code runs in the current thread, with no new thread. join() waits for a thread to finish.
The race condition problem
When two threads change the same variable, the result can be wrong, because count++ is really three steps (read, add, write).
public class Race {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
Runnable job = () -> {
for (int i = 0; i < 100_000; i++) {
count++; // not safe
}
};
Thread a = new Thread(job);
Thread b = new Thread(job);
a.start(); b.start();
a.join(); b.join();
System.out.println("Expected 200000, and the result is correct: " + (count == 200_000));
}
}
Expected 200000, and the result is correct: false
On a normal computer the answer is almost always not correct, and it is different on every run. That is why this is a dangerous bug.
Fix with synchronized
public class Safe {
static int count = 0;
static synchronized void increment() { // only one thread at a time
count++;
}
public static void main(String[] args) throws InterruptedException {
Runnable job = () -> {
for (int i = 0; i < 100_000; i++) {
increment();
}
};
Thread a = new Thread(job);
Thread b = new Thread(job);
a.start(); b.start();
a.join(); b.join();
System.out.println(count);
}
}
200000
For counters, AtomicInteger is simpler and faster:
import java.util.concurrent.atomic.AtomicInteger;
public class Atomic {
public static void main(String[] args) throws InterruptedException {
AtomicInteger count = new AtomicInteger();
Runnable job = () -> {
for (int i = 0; i < 100_000; i++) {
count.incrementAndGet();
}
};
Thread a = new Thread(job);
Thread b = new Thread(job);
a.start(); b.start();
a.join(); b.join();
System.out.println(count.get());
}
}
200000
ExecutorService: a pool of threads
In real programs you do not create threads by hand. You give tasks to an ExecutorService, which reuses threads.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Pool {
public static void main(String[] args) throws Exception {
try (ExecutorService pool = Executors.newFixedThreadPool(3)) {
List<Future<Integer>> results = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
int n = i;
results.add(pool.submit(() -> n * n)); // a Callable returns a value
}
for (Future<Integer> f : results) {
System.out.println(f.get());
}
}
}
}
1
4
9
16
25
Virtual threads (Java 21+)
Virtual threads are very light threads made by the JVM. You can have hundreds of thousands of them, which is great for programs that wait a lot (web calls, databases).
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class Virtual {
public static void main(String[] args) {
AtomicInteger done = new AtomicInteger();
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
try { Thread.sleep(100); } catch (InterruptedException e) { }
done.incrementAndGet();
});
}
}
System.out.println("Tasks done: " + done.get());
}
}
Tasks done: 10000
Thread safety facts
- Immutable objects (like
Stringand records) are safe to share. - Use
ConcurrentHashMap,CopyOnWriteArrayListandAtomicIntegerinstead of locking by hand. - Do not forget that
ArrayListandHashMapare not thread safe.
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |