Skip to content

Commit

Permalink
[BAEL-3351] - Common Concurrency Pitfalls in Java (eugenp#8104)
Browse files Browse the repository at this point in the history
  • Loading branch information
catalin-burcea authored and ashleyfrieze committed Nov 23, 2019
1 parent 009aac4 commit c552aca
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 3 deletions.
15 changes: 12 additions & 3 deletions core-java-modules/core-java-concurrency-advanced-3/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@
<relativePath>../../parent-java</relativePath>
</parent>

<dependencies>
</dependencies>

<build>
<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>
<resource>
<directory>src/main/resources</directory>
Expand All @@ -28,6 +35,8 @@
</build>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -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");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.baeldung.commonissues;

class Counter {
private int counter = 0;

public void increment() {
counter++;
}

public int getValue() {
return counter;
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit c552aca

Please sign in to comment.