diff --git a/build.gradle.kts b/build.gradle.kts index d299500..4f53853 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("java") + id("io.freefair.lombok") version("8.11") } group = "io.concurrency" @@ -10,6 +11,9 @@ repositories { } dependencies { + implementation("ch.qos.logback:logback-classic:1.4.1") + implementation("org.slf4j:slf4j-api:2.0.3") + testImplementation(platform("org.junit:junit-bom:5.9.1")) testImplementation("org.junit.jupiter:junit-jupiter") } diff --git a/src/main/java/io/concurrency/chapter01/exam01/ConcurrencyExample.java b/src/main/java/io/concurrency/chapter01/exam01/ConcurrencyExample.java index dcae22a..261f41d 100644 --- a/src/main/java/io/concurrency/chapter01/exam01/ConcurrencyExample.java +++ b/src/main/java/io/concurrency/chapter01/exam01/ConcurrencyExample.java @@ -6,8 +6,8 @@ public class ConcurrencyExample { public static void main(String[] args) { - int cpuCores = Runtime.getRuntime().availableProcessors() * 2; -// int cpuCores = 13; +// int cpuCores = Runtime.getRuntime().availableProcessors() * 2; + int cpuCores = 30; // CPU 개수를 초과하는 데이터를 생성 List data = new ArrayList<>(); @@ -20,6 +20,7 @@ public static void main(String[] args) { long sum2 = data.parallelStream() .mapToLong(i -> { try { + System.out.println("Thread: " + Thread.currentThread().getName() + " " + i); Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); diff --git a/src/main/java/io/concurrency/chapter01/exam03/CPUBoundExample.java b/src/main/java/io/concurrency/chapter01/exam03/CPUBoundExample.java index a20b987..b855e71 100644 --- a/src/main/java/io/concurrency/chapter01/exam03/CPUBoundExample.java +++ b/src/main/java/io/concurrency/chapter01/exam03/CPUBoundExample.java @@ -36,15 +36,15 @@ public static void main(String[] args) throws InterruptedException { }); futures.add(future); } - futures.forEach(f -> { - try { - f.get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - }); +// futures.forEach(f -> { +// try { +// f.get(); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } catch (ExecutionException e) { +// throw new RuntimeException(e); +// } +// }); long endTime2 = System.currentTimeMillis(); System.out.println("CPU 개수를 초과하는 데이터를 병렬로 처리하는 데 걸린 시간: " + (endTime2 - startTime2) + "ms"); executorService.shutdown(); diff --git a/src/main/java/io/concurrency/chapter01/exam03/IOBoundExample.java b/src/main/java/io/concurrency/chapter01/exam03/IOBoundExample.java index d21be0b..1e9c01f 100644 --- a/src/main/java/io/concurrency/chapter01/exam03/IOBoundExample.java +++ b/src/main/java/io/concurrency/chapter01/exam03/IOBoundExample.java @@ -17,7 +17,7 @@ public static void main(String[] args) { // IO 가 집중 되는 작업 for (int j = 0; j < 5; j++) { - Files.readAllLines(Path.of("D:\\lecture\\Java-Concurrency-Programming\\Java-Concurrency-Programming\\src\\chapter01\\exam03\\sample.txt")); + Files.readAllLines(Path.of("/Users/youngjun/study/Java-Concurrency-Programming/src/main/java/io/concurrency/chapter01/exam03/sample.txt")); System.out.println("스레드: " + Thread.currentThread().getName() +", " +j); // IO Bound 일때 ContextSwitching 이 일어난다 } diff --git a/src/main/java/io/concurrency/chapter02/exam02/MultiThreadAppTerminatedExample.java b/src/main/java/io/concurrency/chapter02/exam02/MultiThreadAppTerminatedExample.java index 5d30950..69a1206 100644 --- a/src/main/java/io/concurrency/chapter02/exam02/MultiThreadAppTerminatedExample.java +++ b/src/main/java/io/concurrency/chapter02/exam02/MultiThreadAppTerminatedExample.java @@ -4,7 +4,7 @@ public class MultiThreadAppTerminatedExample { public static void main(String[] args) { for (int i = 0; i < 3; i++) { - Thread thread = new Thread(new ThreadStackExample.MyRunnable(i)); + Thread thread = new Thread(new MyRunnable(i)); thread.start(); } diff --git a/src/main/java/io/concurrency/chapter02/exam03/StatusTest.java b/src/main/java/io/concurrency/chapter02/exam03/StatusTest.java new file mode 100644 index 0000000..677bbc0 --- /dev/null +++ b/src/main/java/io/concurrency/chapter02/exam03/StatusTest.java @@ -0,0 +1,8 @@ +package io.concurrency.chapter02.exam03; + +public class StatusTest { + public static void main(String[] args) { + Thread thread = new Thread(() -> System.out.println("hahaha")); + System.out.println(thread.getState()); + } +} diff --git a/src/main/java/io/concurrency/chapter03/exam01/BasicSleepExample.java b/src/main/java/io/concurrency/chapter03/exam01/BasicSleepExample.java index 0f57ae5..a850a17 100644 --- a/src/main/java/io/concurrency/chapter03/exam01/BasicSleepExample.java +++ b/src/main/java/io/concurrency/chapter03/exam01/BasicSleepExample.java @@ -8,6 +8,7 @@ public static void main(String[] args) { System.out.println("Hello World"); } catch (InterruptedException e) { + System.out.println("Interrupted"); throw new RuntimeException(e); } } diff --git a/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java b/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java index d2c4472..861485b 100644 --- a/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java +++ b/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java @@ -18,7 +18,7 @@ public static void main(String[] args) throws InterruptedException { sleepingThread.start(); - Thread.sleep(1000); + Thread.sleep(3000); // sleepingThread.interrupt(); } diff --git a/src/main/java/io/concurrency/chapter04/exam01/DefaultExceptionHandlerExample.java b/src/main/java/io/concurrency/chapter04/exam01/DefaultExceptionHandlerExample.java index 2f3f6d4..5ec1520 100644 --- a/src/main/java/io/concurrency/chapter04/exam01/DefaultExceptionHandlerExample.java +++ b/src/main/java/io/concurrency/chapter04/exam01/DefaultExceptionHandlerExample.java @@ -1,19 +1,14 @@ package io.concurrency.chapter04.exam01; -import java.util.logging.Level; -import java.util.logging.Logger; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class DefaultExceptionHandlerExample { public static void main(String[] args) { // 모든 스레드의 예외에 대한 기본 핸들러 설정 - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - System.out.println(t.getName() + " 에서 예외 발생 " + e); - } - }); + Thread.setDefaultUncaughtExceptionHandler(defaultThreadExceptionHandler()); // 예외를 발생시키는 여러 스레드 Thread thread1 = new Thread(() -> { @@ -21,10 +16,14 @@ public void uncaughtException(Thread t, Throwable e) { }); Thread thread2 = new Thread(() -> { - throw new RuntimeException("스레드 2 예외!"); + throw new IllegalStateException("스레드 2 예외!"); }); thread1.start(); thread2.start(); } + + private static Thread.UncaughtExceptionHandler defaultThreadExceptionHandler() { + return (thread, exception) -> log.info("{}에서 예외 발생 : {}", thread.getName(), exception.getMessage()); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam01/ThreadExceptionExample.java b/src/main/java/io/concurrency/chapter04/exam01/ThreadExceptionExample.java index f730bb0..8e57314 100644 --- a/src/main/java/io/concurrency/chapter04/exam01/ThreadExceptionExample.java +++ b/src/main/java/io/concurrency/chapter04/exam01/ThreadExceptionExample.java @@ -1,5 +1,8 @@ package io.concurrency.chapter04.exam01; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class ThreadExceptionExample { public static void main(String[] args) { @@ -8,13 +11,13 @@ public static void main(String[] args) { new Thread(() -> { throw new RuntimeException("스레드 1 예외!"); }).start(); - }catch(Exception e){ + } catch (Exception e) { sendNotificationToAdmin(e); } } private static void sendNotificationToAdmin(Throwable e) { - System.out.println("관리자에게 알림: " + e.getMessage()); + log.info("Notify to admin", e); } } diff --git a/src/main/java/io/concurrency/chapter04/exam01/UncaughtExceptionHandlerExample.java b/src/main/java/io/concurrency/chapter04/exam01/UncaughtExceptionHandlerExample.java index 1f260e6..83c6aaf 100644 --- a/src/main/java/io/concurrency/chapter04/exam01/UncaughtExceptionHandlerExample.java +++ b/src/main/java/io/concurrency/chapter04/exam01/UncaughtExceptionHandlerExample.java @@ -1,10 +1,12 @@ package io.concurrency.chapter04.exam01; +import lombok.extern.slf4j.Slf4j; + import java.util.logging.Level; import java.util.logging.Logger; +@Slf4j public class UncaughtExceptionHandlerExample { - private static final Logger LOGGER = Logger.getLogger(UncaughtExceptionHandlerExample.class.getName()); public static void main(String[] args) { Thread thread = new Thread(() -> { @@ -16,7 +18,7 @@ public static void main(String[] args) { // 스레드의 UncaughtExceptionHandler 설정 thread.setUncaughtExceptionHandler((t, e) -> { - LOGGER.log(Level.SEVERE, t.getName() + " 에서 예외가 발생했습니다.", e); + log.error("{} 에서 예외가 발생했습니다.", t.getName(), e); // 오류가 발생한 경우 알림 서비스 호출 (예: 이메일 또는 Slack 알림) sendNotificationToAdmin(e); diff --git a/src/main/java/io/concurrency/chapter11/exam12/CustomForkJoinPoolExample.java b/src/main/java/io/concurrency/chapter11/exam12/CustomForkJoinPoolExample.java index 7c9db85..7977993 100644 --- a/src/main/java/io/concurrency/chapter11/exam12/CustomForkJoinPoolExample.java +++ b/src/main/java/io/concurrency/chapter11/exam12/CustomForkJoinPoolExample.java @@ -1,7 +1,10 @@ package io.concurrency.chapter11.exam12; +import lombok.extern.slf4j.Slf4j; + import java.util.concurrent.ForkJoinPool; +@Slf4j public class CustomForkJoinPoolExample { public static void main(String[] args) { @@ -10,14 +13,18 @@ public static void main(String[] args) { for (int i = 0; i < array.length; i++) { array[i] = i; } - ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()); + int parallelism = Runtime.getRuntime().availableProcessors(); + log.info("Available processors: {}", parallelism); + + + ForkJoinPool pool = new ForkJoinPool(parallelism); CustomRecursiveTask task = new CustomRecursiveTask(array, 0, array.length); long result = pool.invoke(task); - System.out.println("result = " + result); - System.out.println("pool = " + pool); - System.out.println("stealing = " + pool.getStealCount()); + log.info("result: {}", result); + log.info("pool = {}", pool); + log.info("stealing = {}", pool.getStealCount()); pool.shutdown(); } diff --git a/src/main/java/io/concurrency/chapter11/exam12/ForkJoinSumExample.java b/src/main/java/io/concurrency/chapter11/exam12/ForkJoinSumExample.java new file mode 100644 index 0000000..6338276 --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam12/ForkJoinSumExample.java @@ -0,0 +1,69 @@ +package io.concurrency.chapter11.exam12; + +import lombok.extern.slf4j.Slf4j; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveTask; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +@Slf4j +public class ForkJoinSumExample extends RecursiveTask { + private static final int THRESHOLD = 10; + + private final long[] numbers; + private final int start; + private final int end; + + public ForkJoinSumExample(long[] numbers, int start, int end) { + this.numbers = numbers; + this.start = start; + this.end = end; + } + + @Override + protected Long compute() { + if (end - start <= THRESHOLD) { + // Small task : calculate directly + return Arrays.stream(numbers, start, end).sum(); + } else { + // For Big Task : + int middle = (start + end) / 2; + ForkJoinSumExample leftTask = new ForkJoinSumExample(numbers, start, middle); + ForkJoinSumExample rightTask = new ForkJoinSumExample(numbers, middle, end); + + // Run async + leftTask.fork(); + + // Run in current thread + Long rightResult = rightTask.compute(); + + // Merge results + Long leftResult = leftTask.join(); + + return leftResult + rightResult; + } + } + + public static void main(String[] args) { + long[] numbers = LongStream.rangeClosed(1, 1_000_000_000).toArray(); + + ForkJoinPool pool = new ForkJoinPool(); + ForkJoinSumExample task = new ForkJoinSumExample(numbers, 0, numbers.length); + + + Instant startTime = Instant.now(); + Long sum = pool.invoke(task); + log.info("### Sum = {}", sum); + log.info("With ForkJoinPool = {}ms", Duration.between(startTime, Instant.now()).toMillis()); + + + Instant startTime2 = Instant.now(); + long sum2 = Arrays.stream(numbers, 0, numbers.length).sum(); + log.info("### Sum2 = {}", sum2); + log.info("Without ForkJoinPool = {}ms", Duration.between(startTime2, Instant.now()).toMillis()); + } +}