Java concurrency
Created By: chatGPT
Java Concurrency is a powerful feature that allows multiple threads to execute simultaneously. This can improve the performance of applications, especially when dealing with tasks that can run in parallel. In Java, the
java.util.concurrent
package provides a rich set of tools for handling concurrency, including thread pooling, synchronization, and concurrent collections.import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrencyExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Executing task " + taskId + " by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
Synchronization is crucial in a multithreaded environment to prevent race conditions. In Java, synchronized blocks or methods are used to lock resources and ensure that only one thread can access them at a time.
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedExample example = new SynchronizedExample();
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> { example.increment(); });
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("Final count: " + example.getCount());
}
}
Java also provides concurrent collections to handle data safely across threads. For example,
ConcurrentHashMap
allows concurrent access with better performance compared to synchronized maps.import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentMapExample {
public static void main(String[] args) {
ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 10; i++) {
final int key = i;
new Thread(() -> {
map.put(key, "Value " + key);
System.out.println("Inserted key " + key + " by " + Thread.currentThread().getName());
}).start();
}
}
}
Locks provide more flexible thread synchronization than synchronized blocks. The
Lock
interface and its implementations, like ReentrantLock
, allow for finer control over locking. With locks, you can try to acquire a lock without blocking, and they also support interruptible lock waits.import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
LockExample example = new LockExample();
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> { example.increment(); });
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("Final count: " + example.getCount());
}
}