From 13c42ac4dc962de52b66e99fd7b01e0ea14e3a7a Mon Sep 17 00:00:00 2001 From: Catalin Burcea Date: Sat, 23 Nov 2019 11:03:50 +0000 Subject: [PATCH] [BAEL-3351] - Common Concurrency Pitfalls in Java (#8104) --- .../core-java-concurrency-advanced-3/pom.xml | 15 ++++-- .../CollectionsConcurrencyIssues.java | 53 +++++++++++++++++++ .../com/baeldung/commonissues/Counter.java | 13 +++++ .../commonissues/DeadlockExample.java | 42 +++++++++++++++ ...SimpleDateFormatThreadUnsafetyExample.java | 35 ++++++++++++ .../commonissues/SynchronizedCounter.java | 13 +++++ .../SynchronizedVolatileCounter.java | 13 +++++ 7 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java create mode 100644 core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java diff --git a/core-java-modules/core-java-concurrency-advanced-3/pom.xml b/core-java-modules/core-java-concurrency-advanced-3/pom.xml index cc7b7b1e70..5858232001 100644 --- a/core-java-modules/core-java-concurrency-advanced-3/pom.xml +++ b/core-java-modules/core-java-concurrency-advanced-3/pom.xml @@ -14,11 +14,18 @@ ../../parent-java - - - core-java-concurrency-advanced-3 + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + src/main/resources @@ -28,6 +35,8 @@ + 1.8 + 1.8 diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java new file mode 100644 index 0000000000..cd68bf0709 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/CollectionsConcurrencyIssues.java @@ -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 list = Collections.synchronizedList(new ArrayList<>()); + if (!list.contains("foo")) { + list.add("foo"); + } + } + + private void putIfAbsentList_AtomicOperation_ThreadSafe() { + List list = Collections.synchronizedList(new ArrayList<>()); + synchronized (list) { + if (!list.contains("foo")) { + list.add("foo"); + } + } + } + + private void putIfAbsentMap_NonAtomicOperation_ProneToConcurrencyIssues() { + Map map = new ConcurrentHashMap<>(); + if (!map.containsKey("foo")) { + map.put("foo", "bar"); + } + } + + private void putIfAbsentMap_AtomicOperation_BetterApproach() { + Map map = new ConcurrentHashMap<>(); + synchronized (map) { + if (!map.containsKey("foo")) { + map.put("foo", "bar"); + } + } + } + + private void putIfAbsentMap_AtomicOperation_BestApproach() { + Map map = new ConcurrentHashMap<>(); + map.putIfAbsent("foo", "bar"); + } + + private void computeIfAbsentMap_AtomicOperation() { + Map map = new ConcurrentHashMap<>(); + map.computeIfAbsent("foo", key -> key + "bar"); + } + +} diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java new file mode 100644 index 0000000000..53892b9ad6 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/Counter.java @@ -0,0 +1,13 @@ +package com.baeldung.commonissues; + +class Counter { + private int counter = 0; + + public void increment() { + counter++; + } + + public int getValue() { + return counter; + } +} diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java new file mode 100644 index 0000000000..b7b65d1197 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/DeadlockExample.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java new file mode 100644 index 0000000000..feb2322569 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SimpleDateFormatThreadUnsafetyExample.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java new file mode 100644 index 0000000000..7054db6356 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedCounter.java @@ -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; + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java new file mode 100644 index 0000000000..5434365ca9 --- /dev/null +++ b/core-java-modules/core-java-concurrency-advanced-3/src/main/java/com/baeldung/commonissues/SynchronizedVolatileCounter.java @@ -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; + } +} \ No newline at end of file