[BAEL-3351] - Common Concurrency Pitfalls in Java (#8104)
This commit is contained in:
parent
7ee5019f7e
commit
13c42ac4dc
|
@ -14,11 +14,18 @@
|
||||||
<relativePath>../../parent-java</relativePath>
|
<relativePath>../../parent-java</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>core-java-concurrency-advanced-3</finalName>
|
<finalName>core-java-concurrency-advanced-3</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
|
@ -28,6 +35,8 @@
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class CollectionsConcurrencyIssues {
|
||||||
|
|
||||||
|
private void putIfAbsentList_NonAtomicOperation_ProneToConcurrencyIssues() {
|
||||||
|
List<String> list = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
if (!list.contains("foo")) {
|
||||||
|
list.add("foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putIfAbsentList_AtomicOperation_ThreadSafe() {
|
||||||
|
List<String> list = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
synchronized (list) {
|
||||||
|
if (!list.contains("foo")) {
|
||||||
|
list.add("foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putIfAbsentMap_NonAtomicOperation_ProneToConcurrencyIssues() {
|
||||||
|
Map<String, String> map = new ConcurrentHashMap<>();
|
||||||
|
if (!map.containsKey("foo")) {
|
||||||
|
map.put("foo", "bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putIfAbsentMap_AtomicOperation_BetterApproach() {
|
||||||
|
Map<String, String> map = new ConcurrentHashMap<>();
|
||||||
|
synchronized (map) {
|
||||||
|
if (!map.containsKey("foo")) {
|
||||||
|
map.put("foo", "bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putIfAbsentMap_AtomicOperation_BestApproach() {
|
||||||
|
Map<String, String> map = new ConcurrentHashMap<>();
|
||||||
|
map.putIfAbsent("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeIfAbsentMap_AtomicOperation() {
|
||||||
|
Map<String, String> map = new ConcurrentHashMap<>();
|
||||||
|
map.computeIfAbsent("foo", key -> key + "bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
class Counter {
|
||||||
|
private int counter = 0;
|
||||||
|
|
||||||
|
public void increment() {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
public class DeadlockExample {
|
||||||
|
|
||||||
|
public static Object lock1 = new Object();
|
||||||
|
public static Object lock2 = new Object();
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
Thread threadA = new Thread(() -> {
|
||||||
|
synchronized (lock1) {
|
||||||
|
System.out.println("ThreadA: Holding lock 1...");
|
||||||
|
sleep();
|
||||||
|
System.out.println("ThreadA: Waiting for lock 2...");
|
||||||
|
|
||||||
|
synchronized (lock2) {
|
||||||
|
System.out.println("ThreadA: Holding lock 1 & 2...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Thread threadB = new Thread(() -> {
|
||||||
|
synchronized (lock2) {
|
||||||
|
System.out.println("ThreadB: Holding lock 2...");
|
||||||
|
sleep();
|
||||||
|
System.out.println("ThreadB: Waiting for lock 1...");
|
||||||
|
|
||||||
|
synchronized (lock1) {
|
||||||
|
System.out.println("ThreadB: Holding lock 1 & 2...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
threadA.start();
|
||||||
|
threadB.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sleep() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class SimpleDateFormatThreadUnsafetyExample {
|
||||||
|
|
||||||
|
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String dateStr = "2019-10-29T11:12:21";
|
||||||
|
|
||||||
|
ExecutorService executorService = Executors.newFixedThreadPool(10);
|
||||||
|
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
executorService.submit(() -> parseDate(dateStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
executorService.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseDate(String dateStr) {
|
||||||
|
try {
|
||||||
|
Date date = simpleDateFormat.parse(dateStr);
|
||||||
|
System.out.println("Successfully Parsed Date " + date);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
System.out.println("ParseError " + e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
class SynchronizedCounter {
|
||||||
|
private int counter = 0;
|
||||||
|
|
||||||
|
public synchronized void increment() {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getValue() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.commonissues;
|
||||||
|
|
||||||
|
class SynchronizedVolatileCounter {
|
||||||
|
private volatile int counter = 0;
|
||||||
|
|
||||||
|
public synchronized void increment() {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue