diff --git a/README.md b/README.md index ba4acf1..5e976b6 100644 --- a/README.md +++ b/README.md @@ -1 +1,25 @@ # Java-Concurrency-Programming +--- +운영체제 기초: https://jaimemin.tistory.com/2357 + +쓰레드 생성 및 실행 구조: https://jaimemin.tistory.com/2369 + +Java 쓰레드 기본 API: https://jaimemin.tistory.com/2374 + +Java 쓰레드 활용: https://jaimemin.tistory.com/2389 + +동기화 개념: https://jaimemin.tistory.com/2392 + +동기화 기법: https://jaimemin.tistory.com/2406 + +synchronized, wait() & notify(), volatile, Deadlock: https://jaimemin.tistory.com/2409 + +Lock, ReentrantLock, ReadWriteLock, ReentrantReadWriteLock: https://jaimemin.tistory.com/2411 + +동기화 도구: https://jaimemin.tistory.com/2424 + +자바 동시성 프레임워크: https://jaimemin.tistory.com/2479 + +ThreadPoolExecutor: https://jaimemin.tistory.com/2484 + +CompletableFuture: https://jaimemin.tistory.com/2503 diff --git a/src/main/java/io/concurrency/chapter02/exam01/ExtendThreadExample.java b/src/main/java/io/concurrency/chapter02/exam01/ExtendThreadExample.java index 6b41e7e..8b37bb7 100644 --- a/src/main/java/io/concurrency/chapter02/exam01/ExtendThreadExample.java +++ b/src/main/java/io/concurrency/chapter02/exam01/ExtendThreadExample.java @@ -1,16 +1,16 @@ package io.concurrency.chapter02.exam01; public class ExtendThreadExample { - public static void main(String[] args) { + public static void main(String[] args) { - MyThread myThread = new MyThread(); - myThread.start(); - } - } + MyThread myThread = new MyThread(); + myThread.start(); + } +} - class MyThread extends Thread{ - @Override - public void run() { - System.out.println(Thread.currentThread().getName() + " :스레드 실행 중.. "); - } - } \ No newline at end of file +class MyThread extends Thread { + @Override + public void run() { + System.out.println(Thread.currentThread().getName() + " :스레드 실행 중.. "); + } +} \ No newline at end of file diff --git a/src/main/java/io/concurrency/chapter02/exam01/ExtendedThread.java b/src/main/java/io/concurrency/chapter02/exam01/ExtendedThread.java new file mode 100644 index 0000000..acab95e --- /dev/null +++ b/src/main/java/io/concurrency/chapter02/exam01/ExtendedThread.java @@ -0,0 +1,15 @@ +package io.concurrency.chapter02.exam01; + +public class ExtendedThread extends Thread { + + public void run() { + for (int i = 0; i < 5; i++) { + System.out.println(String.format("%s Value %d", Thread.currentThread().getId(), i)); + } + } + + public static void main(String[] args) { + ExtendedThread thread = new ExtendedThread(); + thread.start(); + } +} diff --git a/src/main/java/io/concurrency/chapter02/exam01/RunnableImpl.java b/src/main/java/io/concurrency/chapter02/exam01/RunnableImpl.java new file mode 100644 index 0000000..b609446 --- /dev/null +++ b/src/main/java/io/concurrency/chapter02/exam01/RunnableImpl.java @@ -0,0 +1,15 @@ +package io.concurrency.chapter02.exam01; + +class RunnableImpl implements Runnable { + + public void run() { + for (int i = 0; i < 5; i++) { + System.out.println(String.format("%s Value %d", Thread.currentThread().getId(), i)); + } + } + + public static void main(String[] args) { + Thread thread = new Thread(new RunnableImpl()); + thread.start(); + } +} diff --git a/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java b/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java index d2c4472..2b5948f 100644 --- a/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java +++ b/src/main/java/io/concurrency/chapter03/exam01/InterruptSleepExample.java @@ -1,25 +1,25 @@ package io.concurrency.chapter03.exam01; public class InterruptSleepExample { - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws InterruptedException { - Thread sleepingThread = new Thread(() -> { - try { - System.out.println("20초 동안 잠듭니다. 인터럽트되지 않는다면 계속 잠들어 있을 것입니다."); + Thread sleepingThread = new Thread(() -> { + try { + System.out.println("20초 동안 잠듭니다. 인터럽트되지 않는다면 계속 잠들어 있을 것입니다."); - Thread.sleep(20000); // 스레드는 지정된 시간 동안 잠듭니다 + Thread.sleep(20000); // 스레드는 지정된 시간 동안 잠듭니다 - System.out.println("인터럽트 없이 잠에서 깨었습니다."); + System.out.println("인터럽트 없이 잠에서 깨었습니다."); - } catch (InterruptedException e) { - System.out.println("잠들어 있는 동안 인터럽트 되었습니다!"); - } - }); + } catch (InterruptedException e) { + System.out.println("잠들어 있는 동안 인터럽트 되었습니다!"); + } + }); - sleepingThread.start(); + sleepingThread.start(); - Thread.sleep(1000); -// - sleepingThread.interrupt(); - } + Thread.sleep(1000); + + sleepingThread.interrupt(); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam01/ExceptionHandlerExample.java b/src/main/java/io/concurrency/chapter04/exam01/ExceptionHandlerExample.java new file mode 100644 index 0000000..4e70b04 --- /dev/null +++ b/src/main/java/io/concurrency/chapter04/exam01/ExceptionHandlerExample.java @@ -0,0 +1,37 @@ +package io.concurrency.chapter04.exam01; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ExceptionHandlerExample { + + private static final Logger LOGGER = Logger.getLogger(ExceptionHandlerExample.class.getName()); + + public static void main(String[] args) { + + // 모든 쓰레드의 예외에 대한 기본 핸들러 설정 + Thread.setDefaultUncaughtExceptionHandler( + (t, e) -> System.out.println(String.format("%s에서 예외 발생: %s", t.getName(), e))); + + // 예외를 발생시키는 여러 쓰레드 + Thread thread1 = new Thread(() -> { + throw new RuntimeException("쓰레드 1 예외!"); + }); + + Thread thread2 = new Thread(() -> { + throw new RuntimeException("쓰레드 2 예외!"); + }); + thread2.setUncaughtExceptionHandler((t, e) -> { + LOGGER.log(Level.SEVERE, String.format("%s에서 예외가 발생했습니다.", t.getName()), e); + + sendNotificationToSlack(e); + }); + + thread1.start(); + thread2.start(); + } + + private static void sendNotificationToSlack(Throwable e) { + System.out.println(String.format("Slack Notification: %s", e.getMessage())); + } +} diff --git a/src/main/java/io/concurrency/chapter04/exam02/FlagThreadStopExample.java b/src/main/java/io/concurrency/chapter04/exam02/FlagThreadStopExample.java index 86f6a49..7229cad 100644 --- a/src/main/java/io/concurrency/chapter04/exam02/FlagThreadStopExample.java +++ b/src/main/java/io/concurrency/chapter04/exam02/FlagThreadStopExample.java @@ -1,35 +1,35 @@ package io.concurrency.chapter04.exam02; public class FlagThreadStopExample { - // volatile 키워드 추가 - volatile boolean running = true; -// boolean running = true; + // volatile 키워드 추가 + // volatile boolean running = true; + boolean running = true; - public void volatileTest() { - new Thread(() -> { - int count = 0; - while (running) { + public void volatileTest() { + new Thread(() -> { + int count = 0; + while (running) { /*try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); }*/ - count++; - } - System.out.println("Thread 1 종료. Count: " + count); - }).start(); + count++; + } + System.out.println("Thread 1 종료. Count: " + count); + }).start(); - new Thread(() -> { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - System.out.println("Thread 2 종료 중.."); - running = false; - }).start(); - } + new Thread(() -> { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + System.out.println("Thread 2 종료 중.."); + running = false; + }).start(); + } - public static void main(String[] args) { - new FlagThreadStopExample().volatileTest(); - } + public static void main(String[] args) { + new FlagThreadStopExample().volatileTest(); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample.java b/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample.java index 3af0c21..0b20f7b 100644 --- a/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample.java +++ b/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample.java @@ -1,41 +1,42 @@ package io.concurrency.chapter04.exam02; public class InterruptedExceptionThreadStopExample { - public static void main(String[] args) { - Thread worker = new Thread(() -> { - try { - while (true) { - // 스레드의 작업을 수행합니다. - System.out.println("작업 스레드가 실행 중입니다."); - System.out.println("인트럽트 상태 1 : " + Thread.currentThread().isInterrupted()); - Thread.sleep(500); + public static void main(String[] args) { + Thread worker = new Thread(() -> { + try { + while (true) { + System.out.println("작업 쓰레드가 실행 중입니다."); + System.out.println(String.format("인트럽트 상태 1 : %s", Thread.currentThread().isInterrupted())); + Thread.sleep(500); + } + } catch (InterruptedException e) { + /** + * sleep 메서드가 인터럽트되면 InterruptedException을 던지며 + * 이 때 interrupt 상태는 초기화 된다. + * 그렇기 때문에 다시 interrupt 를 호출해 줘야 한다. + */ + System.out.println(String.format("인트럽트 상태 2 : %s", Thread.currentThread().isInterrupted())); + Thread.currentThread().interrupt(); + } - } - } catch (InterruptedException e) { - // sleep 메서드가 인터럽트되면 InterruptedException을 던지며 - // 이 때 interrupt 상태는 초기화 된다. - // 그렇기 때문에 다시 interrupt 를 호출해 줘야 한다. - System.out.println("인트럽트 상태 2 : " + Thread.currentThread().isInterrupted()); - Thread.currentThread().interrupt(); - } - System.out.println("작업 스레드가 중단되었습니다."); - System.out.println("인트럽트 상태 3 : " + Thread.currentThread().isInterrupted()); - }); + System.out.println("작업 쓰레드가 중단되었습니다."); + System.out.println(String.format("인트럽트 상태 3 : %s", Thread.currentThread().isInterrupted())); + }); - Thread stopper = new Thread(() -> { - try { - // 1초 후에 스레드를 중지합니다. - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - worker.interrupt(); - System.out.println("중단 스레드가 작업 스레드를 중단시켰습니다."); - }); + Thread stopper = new Thread(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } - worker.start(); - stopper.start(); - } + worker.interrupt(); + System.out.println("중단 쓰레드가 작업 쓰레드를 중단시켰습니다."); + }); + + worker.start(); + stopper.start(); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample2.java b/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample2.java index ef481dc..ea86906 100644 --- a/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample2.java +++ b/src/main/java/io/concurrency/chapter04/exam02/InterruptedExceptionThreadStopExample2.java @@ -1,40 +1,44 @@ package io.concurrency.chapter04.exam02; public class InterruptedExceptionThreadStopExample2 { - public static void main(String[] args) { - Thread worker = new Thread(() -> { - try { - while (!Thread.currentThread().isInterrupted()) { - // 스레드의 작업을 수행합니다. - System.out.println("작업 스레드가 실행 중입니다."); - System.out.println("인트럽트 상태 1 : " + Thread.currentThread().isInterrupted()); - Thread.sleep(500); - } - } catch (InterruptedException e) { - // sleep 메서드가 인터럽트되면 InterruptedException을 던지며 - // 이 때 interrupt 상태는 초기화 된다. - // 그렇기 때문에 다시 interrupt 를 호출해 줘야 한다. - System.out.println("인트럽트 상태 2 : " + Thread.currentThread().isInterrupted()); - Thread.currentThread().interrupt(); - } - System.out.println("작업 스레드가 중단되었습니다."); - System.out.println("인트럽트 상태 3 : " + Thread.currentThread().isInterrupted()); - }); + public static void main(String[] args) { + Thread worker = new Thread(() -> { + try { + while (!Thread.currentThread().isInterrupted()) { + // 쓰레드의 작업을 수행합니다. + System.out.println("작업 쓰레드가 실행 중입니다."); + System.out.println(String.format("인트럽트 상태 1 : %s", Thread.currentThread().isInterrupted())); + Thread.sleep(500); + } + } catch (InterruptedException e) { + /** + * sleep 메서드가 인터럽트되면 InterruptedException을 던지며 + * 이 때 interrupt 상태는 초기화 된다. + * 그렇기 때문에 다시 interrupt 를 호출해 줘야 한다. + */ + System.out.println(String.format("인트럽트 상태 2 : %s", Thread.currentThread().isInterrupted())); + Thread.currentThread().interrupt(); + } - Thread stopper = new Thread(() -> { - try { - // 1초 후에 스레드를 중지합니다. - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - worker.interrupt(); - System.out.println("중단 스레드가 작업 스레드를 중단시켰습니다."); - }); + System.out.println("작업 쓰레드가 중단되었습니다."); + System.out.println(String.format("인트럽트 상태 3 : %s", Thread.currentThread().isInterrupted())); + }); - worker.start(); - stopper.start(); - } + Thread stopper = new Thread(() -> { + try { + // 1초 후에 쓰레드를 중지합니다. + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + worker.interrupt(); + System.out.println("중단 쓰레드가 작업 쓰레드를 중단시켰습니다."); + }); + + worker.start(); + stopper.start(); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam03/DaemonThreadLifeCycleExample.java b/src/main/java/io/concurrency/chapter04/exam03/DaemonThreadLifeCycleExample.java index ab99018..0ec9d5a 100644 --- a/src/main/java/io/concurrency/chapter04/exam03/DaemonThreadLifeCycleExample.java +++ b/src/main/java/io/concurrency/chapter04/exam03/DaemonThreadLifeCycleExample.java @@ -1,36 +1,33 @@ package io.concurrency.chapter04.exam03; public class DaemonThreadLifeCycleExample { - public static void main(String[] args) throws InterruptedException { - Thread userThread = new Thread(() -> { - try { - Thread.sleep(3000); - System.out.println("사용자 스레드 실행 중.."); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); + public static void main(String[] args) throws InterruptedException { + Thread userThread = new Thread(() -> { + try { + Thread.sleep(3000); + System.out.println("사용자 쓰레드 실행 중.."); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); - Thread daemonThread = new Thread(() -> { - while (true){ - try { - Thread.sleep(500); - System.out.println("데몬 스레드 실행 중.."); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - }); + Thread daemonThread = new Thread(() -> { + while (true) { + try { + Thread.sleep(500); + System.out.println("데몬 쓰레드 실행 중.."); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + }); - daemonThread.setDaemon(true); - daemonThread.setDaemon(false); + daemonThread.setDaemon(true); - userThread.start(); - daemonThread.start(); + userThread.start(); + daemonThread.start(); - - userThread.join(); - - System.out.println("메인 스레드 종료"); - } + userThread.join(); + System.out.println("메인 쓰레드 종료"); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupExample.java b/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupExample.java index 790481a..3551adf 100644 --- a/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupExample.java +++ b/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupExample.java @@ -5,16 +5,12 @@ public class ThreadGroupExample { public static void main(String[] args) { // 메인 스레드 그룹 가져오기 ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); - // 새로운 스레드 그룹 생성 - ThreadGroup customGroup = new ThreadGroup("Custom Thread Group"); - + ThreadGroup customGroup = new ThreadGroup("custom-thread-group"); // 기본 스레드 그룹에 속한 스레드 생성 Thread defaultGroupThread = new Thread(new GroupRunnable(), "DefaultGroupThread"); - // 메인 스레드 그룹에 속한 스레드 생성 Thread mainGroupThread = new Thread(mainGroup, new GroupRunnable(), "MainGroupThread"); - // 직접 생성한 스레드 그룹에 속한 스레드 생성 Thread customGroupThread = new Thread(customGroup, new GroupRunnable(), "CustomGroupThread"); @@ -27,7 +23,9 @@ static class GroupRunnable implements Runnable { @Override public void run() { Thread currentThread = Thread.currentThread(); - System.out.println(currentThread.getName() + " 는 " + currentThread.getThreadGroup().getName() + " 에 속한다"); + + System.out.println( + String.format("%s는 %s에 속한다.", currentThread.getName(), currentThread.getThreadGroup().getName())); } } } diff --git a/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupInterruptExample.java b/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupInterruptExample.java index 4ea8211..6f83168 100644 --- a/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupInterruptExample.java +++ b/src/main/java/io/concurrency/chapter04/exam04/ThreadGroupInterruptExample.java @@ -1,13 +1,14 @@ package io.concurrency.chapter04.exam04; public class ThreadGroupInterruptExample { + public static void main(String[] args) throws InterruptedException { ThreadGroup topGroup = new ThreadGroup("상위그룹"); ThreadGroup subGroup = new ThreadGroup(topGroup, "하위그룹"); Thread topGroupThread = new Thread(topGroup, () -> { - while(true){ + while (true) { System.out.println("상위 그룹 스레드 실행중..."); try { Thread.sleep(500); @@ -19,7 +20,7 @@ public static void main(String[] args) throws InterruptedException { }, "상위그룹스레드"); Thread subGroupThread = new Thread(subGroup, () -> { - while(true){ + while (true) { System.out.println("하위 그룹 스레드 실행중..."); try { Thread.sleep(500); @@ -30,13 +31,28 @@ public static void main(String[] args) throws InterruptedException { } }, "하위그룹스레드"); + Thread subGroupThread2 = new Thread(subGroup, () -> { + while (true) { + System.out.println("하위 그룹 스레드 2 실행중..."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + return; + } + } + }, "하위그룹스레드2"); + topGroupThread.start(); subGroupThread.start(); + subGroupThread2.start(); Thread.sleep(3000); // 스레드들이 실행되게 잠시 대기 System.out.println("그룹 스레드들 중지..."); subGroup.interrupt(); + + Thread.sleep(3000); // 3초 동안 상위 그룹 쓰레드만 실행 topGroup.interrupt(); } } diff --git a/src/main/java/io/concurrency/chapter04/exam05/InheritableThreadLocalExample.java b/src/main/java/io/concurrency/chapter04/exam05/InheritableThreadLocalExample.java index d554e7a..d600cb5 100644 --- a/src/main/java/io/concurrency/chapter04/exam05/InheritableThreadLocalExample.java +++ b/src/main/java/io/concurrency/chapter04/exam05/InheritableThreadLocalExample.java @@ -1,31 +1,31 @@ package io.concurrency.chapter04.exam05; public class InheritableThreadLocalExample { - public static InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal<>(); + public static InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal<>(); - public static void main(String[] args) { + public static void main(String[] args) { - inheritableThreadLocal.set("부모 스레드의 값"); + inheritableThreadLocal.set("부모 쓰레드의 값"); - Thread childThread = new Thread(() -> { - // 부모 스레드로부터 값 상속 - System.out.println("자식 스레드에서 상속받은 값: " + inheritableThreadLocal.get()); + Thread childThread = new Thread(() -> { + // 부모 쓰레드로부터 값 상속 + System.out.println("자식 쓰레드에서 상속받은 값: " + inheritableThreadLocal.get()); - // 자식 스레드에서 값을 변경 - inheritableThreadLocal.set("자식 스레드의 새로운 값"); - System.out.println("자식 스레드에서 설정한 후의 값: " + inheritableThreadLocal.get()); - }); + // 자식 쓰레드에서 값을 변경 + inheritableThreadLocal.set("자식 쓰레드의 새로운 값"); + System.out.println("자식 쓰레드에서 설정한 후의 값: " + inheritableThreadLocal.get()); + }); - childThread.start(); + childThread.start(); - // 자식 스레드가 종료될 것을 기다립니다. - try { - childThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // 자식 쓰레드가 종료될 때까지 대기 + try { + childThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } - // 부모 스레드의 값 확인 - System.out.println("부모 스레드의 값: " + inheritableThreadLocal.get()); - } + // 부모 쓰레드의 값 확인 + System.out.println("부모 쓰레드의 값: " + inheritableThreadLocal.get()); + } } diff --git a/src/main/java/io/concurrency/chapter04/exam05/ThreadPoolThreadLocalExample.java b/src/main/java/io/concurrency/chapter04/exam05/ThreadPoolThreadLocalExample.java index 7ed7cec..f89ffe2 100644 --- a/src/main/java/io/concurrency/chapter04/exam05/ThreadPoolThreadLocalExample.java +++ b/src/main/java/io/concurrency/chapter04/exam05/ThreadPoolThreadLocalExample.java @@ -4,34 +4,29 @@ import java.util.concurrent.Executors; public class ThreadPoolThreadLocalExample { - private static ThreadLocal threadLocal = new ThreadLocal<>(); - - public static void main(String[] args) { - - ExecutorService executor = Executors.newFixedThreadPool(2); // 2개의 스레드를 가진 스레드 풀 생성 - - // 첫 번째 작업: ThreadLocal 값을 설정 - executor.submit(() -> { - threadLocal.set("작업 1의 값"); - System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get()); - // 작업 종료 후 값을 지워야 함 -// threadLocal.remove(); - }); - - // 잠시 대기 - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // 여러 번의 두 번째 작업: ThreadLocal 값을 설정하지 않고 바로 값을 가져와 출력 - for (int i = 0; i < 5; i++) { - executor.submit(() -> { - System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get()); // 예상치 못한 값 출력 가능 - }); - } - - executor.shutdown(); - } + private static ThreadLocal threadLocal = new ThreadLocal<>(); + + public static void main(String[] args) { + + ExecutorService executor = Executors.newFixedThreadPool(2); // 2개의 스레드를 가진 스레드 풀 생성 + + // 첫 번째 작업: ThreadLocal 값을 설정 + executor.submit(() -> { + threadLocal.set("Thread 1의 값"); + + System.out.println(String.format("%s: %s", Thread.currentThread().getName(), threadLocal.get())); + // 작업 종료 후 값을 지워야 함 + // threadLocal.remove(); + }); + + // 여러 번의 두 번째 작업: ThreadLocal 값을 설정하지 않고 바로 값을 가져와 출력 + for (int i = 0; i < 10; i++) { + executor.submit(() -> { + System.out.println( + String.format("%s: %s", Thread.currentThread().getName(), threadLocal.get())); // 예상치 못한 값 출력 가능 + }); + } + + executor.shutdown(); + } } diff --git a/src/main/java/io/concurrency/chapter07/exam01/MultipleMonitorsExample.java b/src/main/java/io/concurrency/chapter07/exam01/MultipleMonitorsExample.java index a764905..ee1a78a 100644 --- a/src/main/java/io/concurrency/chapter07/exam01/MultipleMonitorsExample.java +++ b/src/main/java/io/concurrency/chapter07/exam01/MultipleMonitorsExample.java @@ -1,90 +1,94 @@ package io.concurrency.chapter07.exam01; class BankAccount { - private double balance; - private final Object lock = new Object(); + private double balance; + private final Object lock = new Object(); - public BankAccount(double initialBalance) { - this.balance = initialBalance; - } + public BankAccount(double initialBalance) { + this.balance = initialBalance; + } - public void deposit(double amount) { - synchronized (lock) { - balance += amount; - } - } + public void deposit(double amount) { + synchronized (lock) { + balance += amount; + } + } - public boolean withdraw(double amount) { - synchronized (lock) { - if (balance < amount) { - return false; - } - balance -= amount; - return true; - } - } + public boolean withdraw(double amount) { + synchronized (lock) { + if (balance < amount) { + return false; + } + balance -= amount; + return true; + } + } - public boolean transfer(BankAccount to, double amount) { - synchronized (this.lock) { - if (this.withdraw(amount)) { - synchronized (to.lock) { - to.deposit(amount); - return true; - } - } - return false; - } - } + /** + * 이체 작업은 원자성 보장 필요 + * from의 lock과 to의 lock 모두 필요 + */ + public boolean transfer(BankAccount to, double amount) { + synchronized (this.lock) { + if (this.withdraw(amount)) { + synchronized (to.lock) { + to.deposit(amount); + return true; + } + } + return false; + } + } - public double getBalance() { - synchronized (lock) { - return balance; - } - } + public double getBalance() { + synchronized (lock) { + return balance; + } + } } public class MultipleMonitorsExample { - public static void main(String[] args) { - BankAccount accountA = new BankAccount(1000); - BankAccount accountB = new BankAccount(1000); + public static void main(String[] args) { + BankAccount accountA = new BankAccount(1000); + BankAccount accountB = new BankAccount(1000); - // accountA에서 accountB로 송금하는 스레드 - Thread t1 = new Thread(() -> { - for (int i = 0; i < 10; i++) { - boolean result = accountA.transfer(accountB, 10); - if (result) { - System.out.println("accountA에서 accountB로 10 송금 성공"); - } else { - System.out.println("accountA에서 accountB로 10 송금 실패"); - } - } - }); + // accountA에서 accountB로 송금하는 스레드 + Thread t1 = new Thread(() -> { + for (int i = 0; i < 10; i++) { + boolean result = accountA.transfer(accountB, 10); + if (result) { + System.out.println("accountA에서 accountB로 10 송금 성공"); + } else { + System.out.println("accountA에서 accountB로 10 송금 실패"); + } + } + }); - // accountB에서 accountA로 송금하는 스레드 - Thread t2 = new Thread(() -> { - for (int i = 0; i < 10; i++) { - boolean result = accountB.transfer(accountA, 10); - if (result) { - System.out.println("accountB에서 accountA로 10 송금 성공"); - } else { - System.out.println("accountB에서 accountA로 10 송금 실패"); - } - } - }); + // accountB에서 accountA로 송금하는 스레드 + Thread t2 = new Thread(() -> { + for (int i = 0; i < 10; i++) { + boolean result = accountB.transfer(accountA, 10); + if (result) { + System.out.println("accountB에서 accountA로 10 송금 성공"); + } else { + System.out.println("accountB에서 accountA로 10 송금 실패"); + } + } + }); - t1.start(); - t2.start(); + t1.start(); + t2.start(); - try { - t1.join(); - t2.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + try { + t1.join(); + t2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } - System.out.println("accountA의 최종 잔액: " + accountA.getBalance()); - System.out.println("accountB의 최종 잔액: " + accountB.getBalance()); - } + System.out.println("accountA의 최종 잔액: " + accountA.getBalance()); + System.out.println("accountB의 최종 잔액: " + accountB.getBalance()); + } } \ No newline at end of file diff --git a/src/main/java/io/concurrency/chapter07/exam02/SharedData.java b/src/main/java/io/concurrency/chapter07/exam02/SharedData.java new file mode 100644 index 0000000..978ddf9 --- /dev/null +++ b/src/main/java/io/concurrency/chapter07/exam02/SharedData.java @@ -0,0 +1,43 @@ +package io.concurrency.chapter07.exam02; + +public class SharedData { + + private Object lock = new Object(); + + private boolean conditionVariable = false; + + public void consume() throws InterruptedException { + /** + * wait()은 반드시 synchronized 블록 안에서 실행 + * 그렇지 않을 경우 IllegalMonitorStateException 발생 + */ + synchronized (lock) { + wait(); + } + + /** + * 상태 변수 값이 참과 거짓에 따라 wait()을 실행할 것인지 아닌지 조건 명시 + * wait() 호출하기 전 조건 확인하고 notify() 혹은 notifyAll()로 인해 깨어난 쓰레드도 다음 명령어 수행 전 조건 확인 필요 + * 조건을 확인하는 구문은 반드시 while 구문이여야 하는 이유 + * 1. 알 수 없는 이유로 쓸데ㅡ가 깨어나는 현상인 spurious wakeups가 간혹 일어나는데 이런 쓰레드가 활동을 게시하면 심각한 상황 발생 가능 + * 2. 대기에서 깨어난 쓰레드가 락 획득 후 wait() 구문 이후 명령을 진행하기 전 조건을 확인해보니 다시 wait()을 실행해야하는 상황일 수 있음 + */ + while (!conditionVariable) { + wait(); + } + + // 락 해제하기 전 상태 값을 초기화해서 새롭게 진입하는 쓰레드는 다른 쓰레드에 의해 notify() 할 때까지는 대기 상태로 가도록 + conditionVariable = false; + } + + public void produce() throws InterruptedException { + /** + * notify(), notifyAll()은 반드시 synchronized 블록 안에서 실행 + * 그렇지 않을 경우 IllegalMonitorStateException 발생 + */ + synchronized (lock) { + conditionVariable = true; + notifyAll(); + } + } +} diff --git a/src/main/java/io/concurrency/chapter07/exam03/VolatileExample.java b/src/main/java/io/concurrency/chapter07/exam03/VolatileExample.java index 323841a..e4783a1 100644 --- a/src/main/java/io/concurrency/chapter07/exam03/VolatileExample.java +++ b/src/main/java/io/concurrency/chapter07/exam03/VolatileExample.java @@ -1,35 +1,35 @@ package io.concurrency.chapter07.exam03; public class VolatileExample { - // volatile 키워드 추가 -// volatile boolean running = true; - boolean running = true; + // volatile 키워드 추가 + // volatile boolean running = true; + boolean running = true; - public void volatileTest() { - new Thread(() -> { - int count = 0; - while (running) { + public void volatileTest() { + new Thread(() -> { + int count = 0; + while (running) { // volatile 키워드 없을 경우 캐시에서 불러옴 (이 때문에 무한 루프) /*try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); }*/ - count++; - } - System.out.println("Thread 1 종료. Count: " + count); - }).start(); + count++; + } + System.out.println("Thread 1 종료. Count: " + count); + }).start(); - new Thread(() -> { - try { - Thread.sleep(100); - } catch (InterruptedException ignored) { - } - System.out.println("Thread 2 종료 중.."); - running = false; - }).start(); - } + new Thread(() -> { + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + } + System.out.println("Thread 2 종료 중.."); + running = false; + }).start(); + } - public static void main(String[] args) { - new VolatileExample().volatileTest(); - } + public static void main(String[] args) { + new VolatileExample().volatileTest(); + } } diff --git a/src/main/java/io/concurrency/chapter07/exam03/VolatileExample2.java b/src/main/java/io/concurrency/chapter07/exam03/VolatileExample2.java index 74b24a9..ef220f8 100644 --- a/src/main/java/io/concurrency/chapter07/exam03/VolatileExample2.java +++ b/src/main/java/io/concurrency/chapter07/exam03/VolatileExample2.java @@ -1,46 +1,51 @@ package io.concurrency.chapter07.exam03; public class VolatileExample2 { - private volatile int counter = 0; - - // 쓰기 작업 가시성 보장 - public void increment() { - counter++; - } - - // 읽기 작업 가시성 보장 - public int getCounter() { - return counter; - } - - public static void main(String[] args) { - VolatileExample2 example = new VolatileExample2(); - - // 쓰기 스레드 - Thread writer = new Thread(() -> { - for (int i = 0; i < 1000; i++) { - example.increment(); - } - System.out.println("쓰기 스레드가 쓰기 작업을 마쳤습니다."); - }); - - // 읽기 스레드 - Runnable reader = () -> { - int localValue = -1; - while (localValue < 1000) { - localValue = example.getCounter(); - System.out.println(Thread.currentThread().getName() + " 읽은 값: " + localValue); - try { - Thread.sleep(100); // Reader는 값을 더 천천히 읽는다. - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - }; - - writer.start(); - for (int i = 0; i < 5; i++) { - new Thread(reader).start(); - } - } + private volatile int counter = 0; + + // 쓰기 작업 가시성 보장 + + /** + * 하나의 쓰레드가 쓰기 작업을 하고 여러 개의 쓰레드가 읽기 작업을 할 때는 동시성 보장 + * 허나 volatile 키워드만으로는 N:N 관계는 동시성 보장 X + */ + public void increment() { + counter++; + } + + // 읽기 작업 가시성 보장 + public int getCounter() { + return counter; + } + + public static void main(String[] args) { + VolatileExample2 example = new VolatileExample2(); + + // 쓰기 스레드 + Thread writer = new Thread(() -> { + for (int i = 0; i < 1000; i++) { + example.increment(); + } + System.out.println("쓰기 스레드가 쓰기 작업을 마쳤습니다."); + }); + + // 읽기 스레드 + Runnable reader = () -> { + int localValue = -1; + while (localValue < 1000) { + localValue = example.getCounter(); + System.out.println(Thread.currentThread().getName() + " 읽은 값: " + localValue); + try { + Thread.sleep(100); // Reader는 값을 더 천천히 읽는다. + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }; + + writer.start(); + for (int i = 0; i < 5; i++) { + new Thread(reader).start(); + } + } } diff --git a/src/main/java/io/concurrency/chapter07/exam04/DeadlockObjectsExample.java b/src/main/java/io/concurrency/chapter07/exam04/DeadlockObjectsExample.java index 7f0f9b3..d643c91 100644 --- a/src/main/java/io/concurrency/chapter07/exam04/DeadlockObjectsExample.java +++ b/src/main/java/io/concurrency/chapter07/exam04/DeadlockObjectsExample.java @@ -1,50 +1,54 @@ package io.concurrency.chapter07.exam04; public class DeadlockObjectsExample { - public static void main(String[] args) { + public static void main(String[] args) { - ResourceA resourceA = new ResourceA(); - ResourceB resourceB = new ResourceB(); + ResourceA resourceA = new ResourceA(); + ResourceB resourceB = new ResourceB(); - Thread thread1 = new Thread(() -> { - resourceA.methodA(resourceB); - }); + Thread thread1 = new Thread(() -> { + resourceA.methodA(resourceB); + }); - Thread thread2 = new Thread(() -> { - resourceB.methodB(resourceA); - }); + Thread thread2 = new Thread(() -> { + resourceB.methodB(resourceA); + }); - thread1.start(); - thread2.start(); - } + thread1.start(); + thread2.start(); + } } class ResourceA { - public synchronized void methodA(ResourceB resourceB) { - System.out.println(Thread.currentThread().getName() + ": methodA 실행"); - try { - Thread.sleep(100); // 각 메소드에 지연을 추가하여 데드락 가능성 높임 - } catch (InterruptedException e) {} - resourceB.methodB2(); - } - - public synchronized void methodA2() { - System.out.println(Thread.currentThread().getName() + ": methodA2 실행"); - } + public synchronized void methodA(ResourceB resourceB) { + System.out.println(String.format("%s: methodA 실행", Thread.currentThread().getName())); + + try { + Thread.sleep(100); // 각 메소드에 지연을 추가하여 데드락 가능성 높임 + } catch (InterruptedException e) { + } + resourceB.methodB2(); + } + + public synchronized void methodA2() { + System.out.println(String.format("%s: methodA2 실행", Thread.currentThread().getName())); + } } class ResourceB { - public synchronized void methodB(ResourceA resourceA) { - System.out.println(Thread.currentThread().getName() + ": methodB 실행"); - try { - Thread.sleep(100); // 각 메소드에 지연을 추가하여 데드락 가능성 높임 - } catch (InterruptedException e) {} - resourceA.methodA2(); - } - - public synchronized void methodB2() { - System.out.println(Thread.currentThread().getName() + ": methodB2 실행"); - } + public synchronized void methodB(ResourceA resourceA) { + System.out.println(String.format("%s: methodB 실행", Thread.currentThread().getName())); + + try { + Thread.sleep(100); // 각 메소드에 지연을 추가하여 데드락 가능성 높임 + } catch (InterruptedException e) { + } + resourceA.methodA2(); + } + + public synchronized void methodB2() { + System.out.println(String.format("%s: methodB2 실행", Thread.currentThread().getName())); + } } diff --git a/src/main/java/io/concurrency/chapter07/exam04/DeadlockOrderExample.java b/src/main/java/io/concurrency/chapter07/exam04/DeadlockOrderExample.java index 5cff5ec..e97a330 100644 --- a/src/main/java/io/concurrency/chapter07/exam04/DeadlockOrderExample.java +++ b/src/main/java/io/concurrency/chapter07/exam04/DeadlockOrderExample.java @@ -1,53 +1,53 @@ package io.concurrency.chapter07.exam04; public class DeadlockOrderExample { - private static final Object lock1 = new Object(); - private static final Object lock2 = new Object(); - - public static void main(String[] args) { - Thread thread1 = new Thread(() -> { - process1(); - }); - - Thread thread2 = new Thread(() -> { - process2(); - }); - - thread1.start(); - thread2.start(); - } - - private static void process1() { - synchronized (lock1) { - System.out.println(Thread.currentThread().getName() + " 이 lock1 을 획득하였습니다."); - - try { - // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - synchronized (lock2) { - System.out.println(Thread.currentThread().getName() + " 이 lock2 을 획득하였습니다."); - } - } - } - - private static void process2() { - synchronized (lock2) { - System.out.println(Thread.currentThread().getName() + " 이 lock2 을 획득하였습니다."); - - try { - // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - synchronized (lock1) { - System.out.println(Thread.currentThread().getName() + " 이 lock1 을 획득하였습니다."); - } - } - } + private static final Object lock1 = new Object(); + private static final Object lock2 = new Object(); + + public static void main(String[] args) { + Thread thread1 = new Thread(() -> { + process1(); + }); + + Thread thread2 = new Thread(() -> { + process2(); + }); + + thread1.start(); + thread2.start(); + } + + private static void process1() { + synchronized (lock1) { + System.out.println(String.format("%s 쓰레드가 lock1을 획득했습니다.", Thread.currentThread().getName())); + + try { + // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + synchronized (lock2) { + System.out.println(String.format("%s 쓰레드가 lock2를 획득했습니다.", Thread.currentThread().getName())); + } + } + } + + private static void process2() { + synchronized (lock2) { + System.out.println(String.format("%s 쓰레드가 lock2를 획득했습니다.", Thread.currentThread().getName())); + + try { + // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + synchronized (lock1) { + System.out.println(String.format("%s 쓰레드가 lock1을 획득했습니다.", Thread.currentThread().getName())); + } + } + } } diff --git a/src/main/java/io/concurrency/chapter07/exam04/NonDeadlockOrderExample.java b/src/main/java/io/concurrency/chapter07/exam04/NonDeadlockOrderExample.java index 16ea5aa..87b998b 100644 --- a/src/main/java/io/concurrency/chapter07/exam04/NonDeadlockOrderExample.java +++ b/src/main/java/io/concurrency/chapter07/exam04/NonDeadlockOrderExample.java @@ -1,53 +1,53 @@ package io.concurrency.chapter07.exam04; public class NonDeadlockOrderExample { - private static final Object lock1 = new Object(); - private static final Object lock2 = new Object(); - - public static void main(String[] args) { - Thread thread1 = new Thread(() -> { - process1(); - }); - - Thread thread2 = new Thread(() -> { - process2(); - }); - - thread1.start(); - thread2.start(); - } - - private static void process1() { - synchronized (lock1) { - System.out.println(Thread.currentThread().getName() + " 이 lock1 을 획득하였습니다."); - - try { - // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - synchronized (lock2) { - System.out.println(Thread.currentThread().getName() + " 이 lock2 을 획득하였습니다."); - } - } - } - - private static void process2() { - synchronized (lock1) { - System.out.println(Thread.currentThread().getName() + " 이 lock2 을 획득하였습니다."); - - try { - // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - synchronized (lock2) { - System.out.println(Thread.currentThread().getName() + " 이 lock1 을 획득하였습니다."); - } - } - } + private static final Object lock1 = new Object(); + private static final Object lock2 = new Object(); + + public static void main(String[] args) { + Thread thread1 = new Thread(() -> { + process1(); + }); + + Thread thread2 = new Thread(() -> { + process2(); + }); + + thread1.start(); + thread2.start(); + } + + private static void process1() { + synchronized (lock1) { + System.out.println(String.format("%s 쓰레드가 lock1을 획득했습니다", Thread.currentThread().getName())); + + try { + // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + synchronized (lock2) { + System.out.println(String.format("%s 쓰레드가 lock2를 획득했습니다", Thread.currentThread().getName())); + } + } + } + + private static void process2() { + synchronized (lock1) { + System.out.println(String.format("%s 쓰레드가 lock2를 획득했습니다", Thread.currentThread().getName())); + + try { + // 스레드 간의 경쟁 조건을 만들기 위해 잠시 대기 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + synchronized (lock2) { + System.out.println(String.format("%s 쓰레드가 lock1을 획득했습니다", Thread.currentThread().getName())); + } + } + } } diff --git a/src/main/java/io/concurrency/chapter08/exam01/LockOrderExample.java b/src/main/java/io/concurrency/chapter08/exam01/LockOrderExample.java index d00dd63..ed45710 100644 --- a/src/main/java/io/concurrency/chapter08/exam01/LockOrderExample.java +++ b/src/main/java/io/concurrency/chapter08/exam01/LockOrderExample.java @@ -1,28 +1,30 @@ package io.concurrency.chapter08.exam01; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockOrderExample { + private static final ReentrantLock lock1 = new ReentrantLock(); + private static final ReentrantLock lock2 = new ReentrantLock(); public static void main(String[] args) { Thread thread = new Thread(() -> { lock1.lock(); // 1번 락 획득 try { - System.out.println("스레드가 1번 락을 획득했습니다."); + System.out.println("쓰레드가 1번 락을 획득했습니다."); lock2.lock(); // 2번 락 획득 + try { - System.out.println("스레드가 2번 락을 획득했습니다."); + System.out.println("쓰레드가 2번 락을 획득했습니다."); } finally { lock1.unlock(); // 1번 락 해제 - System.out.println("스레드가 1번 락을 해제했습니다."); + System.out.println("쓰레드가 1번 락을 해제했습니다."); } } finally { lock2.unlock(); // 1번 락 해제 - System.out.println("스레드가 2번 락을 해제했습니다."); + System.out.println("쓰레드가 2번 락을 해제했습니다."); } }); diff --git a/src/main/java/io/concurrency/chapter08/exam03/ReadWriteLockExample.java b/src/main/java/io/concurrency/chapter08/exam03/ReadWriteLockExample.java index 20eb973..ec7e8e3 100644 --- a/src/main/java/io/concurrency/chapter08/exam03/ReadWriteLockExample.java +++ b/src/main/java/io/concurrency/chapter08/exam03/ReadWriteLockExample.java @@ -10,8 +10,10 @@ public static void main(String[] args) { Thread reader1 = new Thread(() -> { readWriteLock.readLock().lock(); + try { - System.out.println("읽기 스레드 1이 데이터를 읽고 있습니다. 데이터: " + sharedData.getData()); + System.out.println(String.format("%s: 읽기 쓰레드 1이 데이터를 읽고 있습니다. 데이터: %s", System.currentTimeMillis(), + sharedData.getData())); try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -24,8 +26,10 @@ public static void main(String[] args) { Thread reader2 = new Thread(() -> { readWriteLock.readLock().lock(); + try { - System.out.println("읽기 스레드 2가 데이터를 읽고 있습니다. 데이터: " + sharedData.getData()); + System.out.println(String.format("%s: 읽기 쓰레드 2가 데이터를 읽고 있습니다. 데이터: %s", System.currentTimeMillis(), + sharedData.getData())); try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -38,15 +42,17 @@ public static void main(String[] args) { Thread writer = new Thread(() -> { readWriteLock.writeLock().lock(); + try { - System.out.println("쓰기 스레드가 데이터를 쓰고 있습니다"); + System.out.println(String.format("%s: 쓰기 쓰레드가 데이터를 쓰고 있습니다", System.currentTimeMillis())); sharedData.setData(40); try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } - System.out.println("쓰기 스레드가 데이터를 변경 했습니다. 데이터: " + sharedData.getData()); + System.out.println(String.format("%s: 쓰기 쓰레드가 데이터를 변경 했습니다. 데이터: %s", System.currentTimeMillis(), + sharedData.getData())); } finally { readWriteLock.writeLock().unlock(); } @@ -56,7 +62,9 @@ public static void main(String[] args) { reader1.start(); reader2.start(); } - static class SharedData{ + + static class SharedData { + private int data = 0; public int getData() { diff --git a/src/main/java/io/concurrency/chapter08/exam03/ReentrantReadWriteLockAPIExample.java b/src/main/java/io/concurrency/chapter08/exam03/ReentrantReadWriteLockAPIExample.java index 512dedb..9fd6560 100644 --- a/src/main/java/io/concurrency/chapter08/exam03/ReentrantReadWriteLockAPIExample.java +++ b/src/main/java/io/concurrency/chapter08/exam03/ReentrantReadWriteLockAPIExample.java @@ -3,97 +3,94 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReentrantReadWriteLockAPIExample { - private static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); - - public int getQueueLength() { - return rwLock.getQueueLength(); - } - - public int getReadHoldCount() { - ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock(); - return rwLock.getReadHoldCount(); - } - - public int getReadLockCount() { - return rwLock.getReadLockCount(); - } - - public int getWriteHoldCount() { - ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); - return rwLock.getWriteHoldCount(); - } - - public boolean hasQueuedThread(Thread thread) { - return rwLock.hasQueuedThread(thread); - } - - public boolean hasQueuedThreads() { - return rwLock.hasQueuedThreads(); - } - - public boolean isFair() { - return rwLock.isFair(); - } - - public boolean isWriteLocked() { - return rwLock.isWriteLocked(); - } - - public boolean isWriteLockedByCurrentThread() { - ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); - return rwLock.isWriteLockedByCurrentThread(); - } - - public static void main(String[] args) { - ReentrantReadWriteLockAPIExample example = new ReentrantReadWriteLockAPIExample(); - - - Thread thread1 = new Thread(() -> { - - rwLock.readLock().lock(); - try { - System.out.println("Has Queued Thread: " + example.hasQueuedThread(Thread.currentThread())); - Thread.sleep(1000); // 스레드 2가 Lock을 보유한 상태에서 대기 - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - rwLock.readLock().unlock(); - } - - }); - - Thread thread2 = new Thread(() -> { - rwLock.writeLock().lock(); - try { - System.out.println("Has Queued Thread: " + example.hasQueuedThread(Thread.currentThread())); - Thread.sleep(1000); // 스레드 2가 Lock을 보유한 상태에서 대기 - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - rwLock.writeLock().unlock(); - } - - }); - - thread1.start(); - thread2.start(); - - try { - Thread.sleep(500); // 메인 스레드 대기 - } catch (InterruptedException e) { - e.printStackTrace(); - } - - - System.out.println("Queue Length: " + example.getQueueLength()); - System.out.println("Read Hold Count: " + example.getReadHoldCount()); - System.out.println("Read Lock Count: " + example.getReadLockCount()); - System.out.println("Write Hold Count: " + example.getWriteHoldCount()); - System.out.println("Has Queued Threads: " + example.hasQueuedThreads()); - System.out.println("Is Fair: " + example.isFair()); - System.out.println("Is Write Locked: " + example.isWriteLocked()); - System.out.println("Is Write Locked By Current Thread: " + example.isWriteLockedByCurrentThread()); - - - } + private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + public int getQueueLength() { + return readWriteLock.getQueueLength(); + } + + public int getReadHoldCount() { + ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock(); + + return readWriteLock.getReadHoldCount(); + } + + public int getReadLockCount() { + return readWriteLock.getReadLockCount(); + } + + public int getWriteHoldCount() { + ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock(); + + return readWriteLock.getWriteHoldCount(); + } + + public boolean hasQueuedThread(Thread thread) { + return readWriteLock.hasQueuedThread(thread); + } + + public boolean hasQueuedThreads() { + return readWriteLock.hasQueuedThreads(); + } + + public boolean isFair() { + return readWriteLock.isFair(); + } + + public boolean isWriteLocked() { + return readWriteLock.isWriteLocked(); + } + + public boolean isWriteLockedByCurrentThread() { + ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock(); + + return readWriteLock.isWriteLockedByCurrentThread(); + } + + public static void main(String[] args) { + ReentrantReadWriteLockAPIExample example = new ReentrantReadWriteLockAPIExample(); + + Thread thread1 = new Thread(() -> { + readWriteLock.readLock().lock(); + + try { + System.out.println("Has Queued Thread: " + example.hasQueuedThread(Thread.currentThread())); + Thread.sleep(1000); // 스레드 2가 Lock을 보유한 상태에서 대기 + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + readWriteLock.readLock().unlock(); + } + }); + + Thread thread2 = new Thread(() -> { + readWriteLock.writeLock().lock(); + try { + System.out.println("Has Queued Thread: " + example.hasQueuedThread(Thread.currentThread())); + Thread.sleep(1000); // 스레드 2가 Lock을 보유한 상태에서 대기 + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + readWriteLock.writeLock().unlock(); + } + }); + + thread1.start(); + thread2.start(); + + try { + Thread.sleep(500); // 메인 스레드 대기 + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("Queue Length: " + example.getQueueLength()); + System.out.println("Read Hold Count: " + example.getReadHoldCount()); + System.out.println("Read Lock Count: " + example.getReadLockCount()); + System.out.println("Write Hold Count: " + example.getWriteHoldCount()); + System.out.println("Has Queued Threads: " + example.hasQueuedThreads()); + System.out.println("Is Fair: " + example.isFair()); + System.out.println("Is Write Locked: " + example.isWriteLocked()); + System.out.println("Is Write Locked By Current Thread: " + example.isWriteLockedByCurrentThread()); + } } diff --git a/src/main/java/io/concurrency/chapter09/exam01/MultiThreadCASExample.java b/src/main/java/io/concurrency/chapter09/exam01/MultiThreadCASExample.java index 5695fac..7f68d35 100644 --- a/src/main/java/io/concurrency/chapter09/exam01/MultiThreadCASExample.java +++ b/src/main/java/io/concurrency/chapter09/exam01/MultiThreadCASExample.java @@ -3,24 +3,35 @@ import java.util.concurrent.atomic.AtomicInteger; public class MultiThreadCASExample { + + private static int MAX = 100000; + private static AtomicInteger value = new AtomicInteger(0); + private static final int NUM_THREADS = 3; + public static void main(String[] args) { Thread[] threads = new Thread[NUM_THREADS]; for (int i = 0; i < NUM_THREADS; i++) { threads[i] = new Thread(() -> { - for (int j = 0; j < 100000; j++) { + for (int j = 0; j < MAX; j++) { int expectedValue, newValue; + do { expectedValue = value.get(); newValue = expectedValue + 1; } while (!value.compareAndSet(expectedValue, newValue)); // 반환 값이 false 이면 true 가 반환 될 때 까지 재시도 - System.out.println(Thread.currentThread().getName() + ":" + expectedValue + " , " + newValue); + + System.out.println( + String.format("%s: expectedValue: %d, newValue: %d", Thread.currentThread().getName(), + expectedValue, newValue)); } }); + threads[i].start(); } + for (Thread thread : threads) { try { thread.join(); @@ -28,6 +39,7 @@ public static void main(String[] args) { e.printStackTrace(); } } - System.out.println("Final value: " + value.get()); + + System.out.println(String.format("최종 값: %d", value.get())); } } diff --git a/src/main/java/io/concurrency/chapter09/exam02/AtomicIntegerAPIExample.java b/src/main/java/io/concurrency/chapter09/exam02/AtomicIntegerAPIExample.java index 6572a71..cb9599d 100644 --- a/src/main/java/io/concurrency/chapter09/exam02/AtomicIntegerAPIExample.java +++ b/src/main/java/io/concurrency/chapter09/exam02/AtomicIntegerAPIExample.java @@ -5,28 +5,27 @@ public class AtomicIntegerAPIExample { - public static void main(String[] args) throws InterruptedException { - AtomicInteger atomicInt = new AtomicInteger(10); - int currentValue = atomicInt.get(); - System.out.println("Current value: " + currentValue); // 10 + public static void main(String[] args) throws InterruptedException { + AtomicInteger atomicInteger = new AtomicInteger(10); + int currentValue = atomicInteger.get(); + System.out.println(String.format("현재 값: %d", currentValue)); - atomicInt.set(20); - System.out.println("New value: " + atomicInt.get()); // 20 + atomicInteger.set(20); + System.out.println(String.format("변경된 값: %d", atomicInteger.get())); - int previousValue = atomicInt.getAndSet(30); - System.out.println("Previous value: " + previousValue); // 20 System.out.println("New value: " + atomicInt.get()); // 30 + int previousValue = atomicInteger.getAndSet(30); + System.out.println(String.format("변경 전 값: %d", previousValue)); - int newValue = atomicInt.incrementAndGet(); - System.out.println("New value after increment: " + newValue); // 31 + int newValue = atomicInteger.incrementAndGet(); + System.out.println(String.format("변경 후 값: %d", newValue)); - boolean updated = atomicInt.compareAndSet(31, 40); - System.out.println("Update successful? " + updated); // true - System.out.println("New value: " + atomicInt.get()); // 40 + boolean updated = atomicInteger.compareAndSet(31, 40); + System.out.println(String.format("성공적으로 값을 변경? %s", updated)); // true + System.out.println(String.format("변경 후 값: %d", atomicInteger.get())); - IntUnaryOperator addFive = value -> value + 5; - int previousValue2 = atomicInt.getAndUpdate(addFive); - System.out.println("Previous value: " + previousValue2); // 40 System.out.println("Updated value: " + atomicInt.get()); // 45 - System.out.println("Next value: " + atomicInt.get()); // 40 System.out.println("Updated value: " + atomicInt.get()); // 45 - - } + IntUnaryOperator addFive = value -> value + 5; + int previousValue2 = atomicInteger.getAndUpdate(addFive); + System.out.println(String.format("변경 전 값: %d", previousValue2)); + System.out.println(String.format("변경 후 값: %d", atomicInteger.get())); + } } diff --git a/src/main/java/io/concurrency/chapter09/exam02/AtomicReferenceExample.java b/src/main/java/io/concurrency/chapter09/exam02/AtomicReferenceExample.java index 3098df7..2903c20 100644 --- a/src/main/java/io/concurrency/chapter09/exam02/AtomicReferenceExample.java +++ b/src/main/java/io/concurrency/chapter09/exam02/AtomicReferenceExample.java @@ -5,19 +5,17 @@ public class AtomicReferenceExample { public static void main(String[] args) { - User user1 = new User("Alice", 25); User user2 = new User("Bob", 30); - AtomicReference atomicReference = new AtomicReference<>(user2); Thread thread1 = new Thread(() -> { User updateUser = new User("Carol", 40); boolean success = atomicReference.compareAndSet(user1, updateUser); if (success) { - System.out.println("스레드 1 이 " + updateUser + " 로 변경에 성공했습니다."); + System.out.println("쓰레드 1 이 " + updateUser + " 로 변경에 성공했습니다."); } else { - System.out.println("스레드 1 이 " + updateUser + " 로 변경에 실패했습니다."); + System.out.println("쓰레드 1 이 " + updateUser + " 로 변경에 실패했습니다."); } }); @@ -25,9 +23,9 @@ public static void main(String[] args) { User updateUser = new User("David", 50); boolean success = atomicReference.compareAndSet(user2, updateUser); if (success) { - System.out.println("스레드 2 가 " + updateUser + " 로 변경에 성공했습니다."); + System.out.println("쓰레드 2 가 " + updateUser + " 로 변경에 성공했습니다."); } else { - System.out.println("스레드 2 가 " + updateUser + " 로 변경에 실패했습니다."); + System.out.println("쓰레드 2 가 " + updateUser + " 로 변경에 실패했습니다."); } }); @@ -46,8 +44,10 @@ public static void main(String[] args) { } } -class User{ +class User { + private String name; + private int age; public User(String name, int age) { @@ -66,8 +66,8 @@ public int getAge() { @Override public String toString() { return "User{" + - "name='" + name + '\'' + - ", age=" + age + - '}'; + "name='" + name + '\'' + + ", age=" + age + + '}'; } } diff --git a/src/main/java/io/concurrency/chapter09/exam02/Example.java b/src/main/java/io/concurrency/chapter09/exam02/Example.java new file mode 100644 index 0000000..23d89e0 --- /dev/null +++ b/src/main/java/io/concurrency/chapter09/exam02/Example.java @@ -0,0 +1,22 @@ +package io.concurrency.chapter09.exam02; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class Example { + + public static void main(String[] args) { + /** + * 전달된 값으로 초기값이 설정되며 default 값은 false + */ + AtomicBoolean atomicBoolean = new AtomicBoolean(true); + boolean currentValue = atomicBoolean.get(); + System.out.println(String.format("현재 값: %s", currentValue)); + + atomicBoolean.set(false); + System.out.println(String.format("변경된 값: %s", atomicBoolean.get())); + + boolean prevValue = atomicBoolean.getAndSet(true); + System.out.println(String.format("변경 전 값: %s", prevValue)); + System.out.println(String.format("변경 후 값: %s", atomicBoolean.get())); + } +} diff --git a/src/main/java/io/concurrency/chapter09/exam02/Example2.java b/src/main/java/io/concurrency/chapter09/exam02/Example2.java new file mode 100644 index 0000000..f8e1d8b --- /dev/null +++ b/src/main/java/io/concurrency/chapter09/exam02/Example2.java @@ -0,0 +1,29 @@ +package io.concurrency.chapter09.exam02; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; + +public class Example2 { + + public static void main(String[] args) { + AtomicReference reference = new AtomicReference<>("초기값"); + String currentValue = reference.get(); + System.out.println(String.format("현재 값: %s", currentValue)); + + reference.set("변경된 값"); + System.out.println(String.format("변경된 값: %s", reference.get())); + + boolean success = reference.compareAndSet("변경된 값", "업데이트된 값"); + System.out.println(String.format("변경 성공? %s", success)); + System.out.println(String.format("현재 값: %s", reference.get())); + + String oldValue = reference.getAndSet("최종 값"); + System.out.println(String.format("변경 전 값: %s", oldValue)); + System.out.println(String.format("변경 후 값: %s", reference.get())); + + UnaryOperator operator = o -> o.concat("!"); + String newValue = reference.updateAndGet(operator); + System.out.println(String.format("변경 후 값: %s", newValue)); + System.out.println(String.format("변경 후 값 검증: %s", reference.get())); + } +} diff --git a/src/main/java/io/concurrency/chapter11/exam07/ThenCombine.java b/src/main/java/io/concurrency/chapter11/exam07/ThenCombine.java new file mode 100644 index 0000000..e84f64e --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam07/ThenCombine.java @@ -0,0 +1,14 @@ +package io.concurrency.chapter11.exam07; + +import java.util.concurrent.CompletableFuture; + +public class ThenCombine { + + public static void main(String[] args) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> 10); + CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> 30); + + Integer multiply = cf.thenCombine(cf2, (result, result2) -> result * result2).join(); + System.out.println(multiply); + } +} diff --git a/src/main/java/io/concurrency/chapter11/exam07/ThenCompose.java b/src/main/java/io/concurrency/chapter11/exam07/ThenCompose.java new file mode 100644 index 0000000..88fb00c --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam07/ThenCompose.java @@ -0,0 +1,14 @@ +package io.concurrency.chapter11.exam07; + +import java.util.concurrent.CompletableFuture; + +public class ThenCompose { + + public static void main(String[] args) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> 10) + .thenCompose(result -> CompletableFuture.supplyAsync(() -> result * 10)); + + Integer result = cf.join(); + System.out.println(result); + } +} diff --git a/src/main/java/io/concurrency/chapter11/exam08/AllOfExample.java b/src/main/java/io/concurrency/chapter11/exam08/AllOfExample.java index e6dbf80..85ee782 100644 --- a/src/main/java/io/concurrency/chapter11/exam08/AllOfExample.java +++ b/src/main/java/io/concurrency/chapter11/exam08/AllOfExample.java @@ -3,85 +3,55 @@ import java.util.concurrent.CompletableFuture; public class AllOfExample { - public static void main(String[] args) throws InterruptedException { - - ServiceA sa = new ServiceA(); - ServiceB sb = new ServiceB(); - ServiceC sc = new ServiceC(); - - CompletableFuture cf1 = sa.getData1(); - CompletableFuture cf2 = sb.getData2(); - CompletableFuture cf3 = sc.getData3(); - - long started = System.currentTimeMillis(); - CompletableFuture voidCf = CompletableFuture.allOf(cf1, cf2, cf3); - CompletableFuture finalCf = voidCf.thenApply(v -> { - - int result1 = cf1.join(); - int result2 = cf2.join(); - int result3 = cf3.join(); - - System.out.println("result1 = " + result1); - System.out.println("result2 = " + result2); - System.out.println("result3 = " + result3); - - return result1 + result2 + result3; - - }); -// Thread.sleep(2000); - finalCf.join(); - System.out.println("최종 소요 시간: " + (System.currentTimeMillis() - started)); - -// System.out.println("최종결과: " + voidCf); - System.out.println("최종결과: " + finalCf.join()); - System.out.println("메인 스레드 종료"); - } - - static class ServiceA { - - public CompletableFuture getData1() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(1000); - System.out.println("비동기 작업 시작 1"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 10; - }); - } - } - - static class ServiceB { - - public CompletableFuture getData2() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(2000); - System.out.println("비동기 작업 시작 2"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 20; - }); - } - } - - static class ServiceC { - - public CompletableFuture getData3() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(1000); - System.out.println("비동기 작업 시작 3"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 30; - }); - } - } + public static void main(String[] args) throws InterruptedException { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + System.out.println("비동기 작업 시작 1"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 10; + }); + CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(2000); + System.out.println("비동기 작업 시작 2"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 20; + }); + CompletableFuture cf3 = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + System.out.println("비동기 작업 시작 3"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 30; + }); + + long started = System.nanoTime(); + CompletableFuture voidCf = CompletableFuture.allOf(cf, cf2, cf3); + CompletableFuture finalCf = voidCf.thenApply(v -> { + int result = cf.join(); + int result2 = cf2.join(); + int result3 = cf3.join(); + + System.out.println("result = " + result); + System.out.println("result2 = " + result2); + System.out.println("result3 = " + result3); + + return result + result2 + result3; + }); + + finalCf.join(); + System.out.println("최종 소요 시간: " + (System.nanoTime() - started) / 1e9); + System.out.println("최종결과: " + finalCf.join()); + System.out.println("메인 쓰레드 종료"); + } } diff --git a/src/main/java/io/concurrency/chapter11/exam08/AnyOfExample.java b/src/main/java/io/concurrency/chapter11/exam08/AnyOfExample.java index d3a37b1..679bd73 100644 --- a/src/main/java/io/concurrency/chapter11/exam08/AnyOfExample.java +++ b/src/main/java/io/concurrency/chapter11/exam08/AnyOfExample.java @@ -3,75 +3,44 @@ import java.util.concurrent.CompletableFuture; public class AnyOfExample { - public static void main(String[] args) { - - ServiceA sa = new ServiceA(); - ServiceB sb = new ServiceB(); - ServiceC sc = new ServiceC(); - - CompletableFuture cf1 = sa.getData1(); - CompletableFuture cf2 = sb.getData2(); - CompletableFuture cf3 = sc.getData3(); - - long started = System.currentTimeMillis(); - CompletableFuture finalCf = CompletableFuture.anyOf(cf1, cf2, cf3); - finalCf.thenApply(result -> { - return (int)result * 10; - - }); -// Thread.sleep(2000); - finalCf.join(); - System.out.println("최종 소요 시간: " + (System.currentTimeMillis() - started)); - - System.out.println("최종결과: " + finalCf.join()); - System.out.println("메인 스레드 종료"); - } - - static class ServiceA { - - public CompletableFuture getData1() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - System.out.println("비동기 작업 시작 1"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 10; - }); - } - } - - static class ServiceB { - - public CompletableFuture getData2() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(2000); - System.out.println("비동기 작업 시작 2"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 20; - }); - } - } - - static class ServiceC { - - public CompletableFuture getData3() { - // 비동기 작업 시뮬레이션 - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(1000); - System.out.println("비동기 작업 시작 3"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 30; - }); - } - } + public static void main(String[] args) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(500); + System.out.println("비동기 작업 시작 1"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 10; + }); + CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(2000); + System.out.println("비동기 작업 시작 2"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 20; + }); + CompletableFuture cf3 = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + System.out.println("비동기 작업 시작 3"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 30; + }); + + long started = System.nanoTime(); + CompletableFuture finalCf = CompletableFuture.anyOf(cf, cf2, cf3) + .thenApply(result -> (int)result * 10); + finalCf.join(); + System.out.println("최종 소요 시간: " + (System.nanoTime() - started) / 1e9); + System.out.println("최종결과: " + finalCf.join()); + System.out.println("메인 쓰레드 종료"); + } } diff --git a/src/main/java/io/concurrency/chapter11/exam09/ExceptionallyExample.java b/src/main/java/io/concurrency/chapter11/exam09/ExceptionallyExample.java index eff66c5..2e76303 100644 --- a/src/main/java/io/concurrency/chapter11/exam09/ExceptionallyExample.java +++ b/src/main/java/io/concurrency/chapter11/exam09/ExceptionallyExample.java @@ -3,22 +3,26 @@ import java.util.concurrent.CompletableFuture; public class ExceptionallyExample { - public static void main(String[] args) { + public static void main(String[] args) { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + if (System.nanoTime() % 2 != 0) { + try { + Thread.sleep(500); - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - throw new IllegalArgumentException("error"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 10; - }).thenApply(r -> r + 20) - .exceptionally(e -> { - System.out.println("Exception: " + e.getMessage()); - return -1; - }); + throw new RuntimeException("error has occurred"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } - System.out.println("result: " +cf.join()); - } + return 10; + }) + .thenApply(r -> r + 20) + .exceptionally(e -> { + System.out.println("Exception: " + e.getMessage()); + return -1; + }); + + System.out.println("result: " + cf.join()); + } } diff --git a/src/main/java/io/concurrency/chapter11/exam09/HandleExample.java b/src/main/java/io/concurrency/chapter11/exam09/HandleExample.java index 4c5d6c5..17c46a1 100644 --- a/src/main/java/io/concurrency/chapter11/exam09/HandleExample.java +++ b/src/main/java/io/concurrency/chapter11/exam09/HandleExample.java @@ -4,49 +4,55 @@ public class HandleExample { public static void main(String[] args) { - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 10; - }).handle((r, e) ->{ - if(e !=null){ - System.out.println("비동기 예외처리 1: " + e.getMessage()); - return -1; - } - return r; - }); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + return 10; + }).handle((result, error) -> { + if (error != null) { + System.out.println("비동기 예외처리: " + error.getMessage()); + + return -1; + } + + return result; + }); CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - throw new RuntimeException("error"); - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 20; - }).handle((r, e) ->{ - if(e !=null){ - System.out.println("비동기 예외처리 2: " + e.getMessage()); - return -1; - } - return r; - }); - - - CompletableFuture cf3 = cf1.thenCombine(cf2, (r1, r2) -> { - if (r1 == -1 || r2 == -1) { - // 둘 중 하나라도 예외가 발생하면 예외 처리 + if (System.nanoTime() % 2 != 0) { + try { + Thread.sleep(500); + + throw new RuntimeException("error has occurred"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + return 20; + }).handle((result, error) -> { + if (error != null) { + System.out.println("비동기 예외처리 2: " + error.getMessage()); + + return -1; + } + + return result; + }); + + CompletableFuture cf3 = cf1.thenCombine(cf2, (result, result2) -> { + // 둘 중 하나라도 예외가 발생하면 예외 처리 + if (result == -1 || result2 == -1) { return -1; } - // 두 결과를 조합하여 복잡한 작업 수행 - return r1 + r2; + + return result + result2; }); - System.out.println("result: " + cf3.join()); + System.out.println("결과: " + cf3.join()); } } diff --git a/src/main/java/io/concurrency/chapter11/exam09/WhenCompleteExample.java b/src/main/java/io/concurrency/chapter11/exam09/WhenCompleteExample.java index 8e6f527..a4941c4 100644 --- a/src/main/java/io/concurrency/chapter11/exam09/WhenCompleteExample.java +++ b/src/main/java/io/concurrency/chapter11/exam09/WhenCompleteExample.java @@ -4,31 +4,36 @@ import java.util.concurrent.CompletionException; public class WhenCompleteExample { - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws InterruptedException { + CompletableFuture cf = CompletableFuture.supplyAsync(() -> { + if (System.nanoTime() % 2 != 0) { + try { + Thread.sleep(500); - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - throw new RuntimeException("error"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - return 10; - }).whenComplete((r,e) ->{ - if(e != null){ - System.out.println("Exception: " + e.getMessage()); - }else{ - System.out.println("result: " + r); - } - }); + throw new RuntimeException("error has occurred"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } - try { - Thread.sleep(2000); - cf.join(); - }catch(CompletionException e){ - System.out.println("예외 처리를 합니다"); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } + return 10; + }).whenComplete((result, exception) -> { + // 반환 값이 없음 + if (exception != null) { + System.out.println("Exception: " + exception.getMessage()); + } else { + System.out.println("result: " + result); + } + }); + + try { + Thread.sleep(2000); + + cf.join(); + } catch (CompletionException e) { + System.out.println("예외 처리를 합니다"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/io/concurrency/chapter11/exam10/CompleteExample2.java b/src/main/java/io/concurrency/chapter11/exam10/CompleteExample2.java new file mode 100644 index 0000000..3ce7724 --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam10/CompleteExample2.java @@ -0,0 +1,27 @@ +package io.concurrency.chapter11.exam10; + +import java.util.concurrent.CompletableFuture; + +public class CompleteExample2 { + + public static void main(String[] args) { + CompletableFuture cf = new CompletableFuture<>(); + new Thread(() -> { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + cf.complete("작업 완료!"); + }).start(); + + try { + String result = cf.get(); + + System.out.println("비동기 작업 결과: " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/io/concurrency/chapter11/exam10/CompleteOnTimeoutExample.java b/src/main/java/io/concurrency/chapter11/exam10/CompleteOnTimeoutExample.java index 95f59d5..13e8069 100644 --- a/src/main/java/io/concurrency/chapter11/exam10/CompleteOnTimeoutExample.java +++ b/src/main/java/io/concurrency/chapter11/exam10/CompleteOnTimeoutExample.java @@ -4,23 +4,18 @@ import java.util.concurrent.TimeUnit; public class CompleteOnTimeoutExample { - public static void main(String[] args) { + public static void main(String[] args) { + CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(3000); - getData().completeOnTimeout("Hello Java", 2, TimeUnit.SECONDS) - .thenAccept(r -> { - System.out.println("r = " + r); - }).join(); - } - - private static CompletableFuture getData() { - - return CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(2000); - return "Hello World"; - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); - } + return "Hello World"; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }).completeOnTimeout("타임아웃에 따른 기본 메시지", 2, TimeUnit.SECONDS) + .thenAccept(result -> { + System.out.println("result = " + result); + }).join(); + } } diff --git a/src/main/java/io/concurrency/chapter11/exam10/CompletedFutureExample.java b/src/main/java/io/concurrency/chapter11/exam10/CompletedFutureExample.java index 3d32c14..b617626 100644 --- a/src/main/java/io/concurrency/chapter11/exam10/CompletedFutureExample.java +++ b/src/main/java/io/concurrency/chapter11/exam10/CompletedFutureExample.java @@ -3,15 +3,11 @@ import java.util.concurrent.CompletableFuture; public class CompletedFutureExample { - public static void main(String[] args) { + public static void main(String[] args) { + CompletableFuture future = CompletableFuture.completedFuture("미리 완료된 결과"); - CompletableFuture cf = CompletableFuture.completedFuture("Hello World"); - -// CompletableFuture cf2 = new CompletableFuture<>(); -// cf2.complete("Hello World"); - - CompletableFuture finalCf = cf.thenAccept(r -> { - System.out.println("result: " + r); - }); - } + // 결과를 즉시 얻을 수 있음 + String result = future.join(); // join()은 예외 처리를 하지 않는 get() 메서드 + System.out.println("결과: " + result); + } } diff --git a/src/main/java/io/concurrency/chapter11/exam10/completeExceptionallyExample.java b/src/main/java/io/concurrency/chapter11/exam10/completeExceptionallyExample.java index cabb27f..df4a8ff 100644 --- a/src/main/java/io/concurrency/chapter11/exam10/completeExceptionallyExample.java +++ b/src/main/java/io/concurrency/chapter11/exam10/completeExceptionallyExample.java @@ -1,36 +1,31 @@ package io.concurrency.chapter11.exam10; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; public class completeExceptionallyExample { public static void main(String[] args) { + CompletableFuture cf = new CompletableFuture<>(); - CompletableFuture cf1 = new CompletableFuture<>(); - getData(cf1); - CompletableFuture cf2 = cf1 - .thenApply(result -> { - System.out.println(result); - return result.toUpperCase(); - }) - .handle((r, e) -> { - if (e != null) { - System.err.println("Exception: " + e.getMessage()); - return "noname"; - } - return r; - }); + new Thread(() -> { + try { + // 2초 동안 작업 수행 (예: 비동기 작업) + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } - System.out.println("result: " + cf2.join()); - } + cf.completeExceptionally(new RuntimeException("비동기 작업 중 오류 발생")); + }).start(); - private static void getData(CompletableFuture cf) { try { - System.out.println("비동기 작업 수행 중.."); - Thread.sleep(500); -// throw new IllegalArgumentException("error"); - } catch (Exception e) { - cf.completeExceptionally(e); + String result = cf.get(); + + System.out.println("비동기 작업 결과: " + result); + } catch (ExecutionException e) { + System.out.println("예외 발생: " + e.getCause().getMessage()); + } catch (InterruptedException e) { + e.printStackTrace(); } - cf.complete("Hello World"); } } diff --git a/src/main/java/io/concurrency/chapter11/exam10/isCancelledExample.java b/src/main/java/io/concurrency/chapter11/exam10/isCancelledExample.java new file mode 100644 index 0000000..8c12300 --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam10/isCancelledExample.java @@ -0,0 +1,48 @@ +package io.concurrency.chapter11.exam10; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class isCancelledExample { + + public static void main(String[] args) { + CompletableFuture cf = new CompletableFuture<>(); + + new Thread(() -> { + try { + Thread.sleep(2000); + + if (cf.isCancelled()) { + System.out.println("작업이 취소되었습니다."); + + return; + } + + cf.complete("작업 완료!"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + try { + TimeUnit.SECONDS.sleep(1); + boolean cancelled = cf.cancel(true); + + System.out.println("취소 시도 결과: " + cancelled); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (cf.isCancelled()) { + System.out.println("CompletableFuture가 취소되었습니다."); + } else { + try { + String result = cf.get(); + + System.out.println("비동기 작업 결과: " + result); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/io/concurrency/chapter11/exam10/isCompletedExceptionallyAndIsCancelledExample.java b/src/main/java/io/concurrency/chapter11/exam10/isCompletedExceptionallyAndIsCancelledExample.java index 22c179b..3233c24 100644 --- a/src/main/java/io/concurrency/chapter11/exam10/isCompletedExceptionallyAndIsCancelledExample.java +++ b/src/main/java/io/concurrency/chapter11/exam10/isCompletedExceptionallyAndIsCancelledExample.java @@ -2,37 +2,48 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; public class isCompletedExceptionallyAndIsCancelledExample { - public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { - - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> 10); - CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { -// return 20; - throw new RuntimeException("error"); - }); - -// cf2.cancel(true); - - CompletableFuture combinedFuture = - cf1.thenCombine(cf2.exceptionally(e -> 15), (result1, result2) -> { - - if (cf2.isCancelled()) { - return 0; // 취소 완료 - } - else if (cf2.isCompletedExceptionally()) { - return result2; // 예외 완료 - } - else if(cf2.isDone()) { - return result1 + result2; // 정상 완료 - } - else return -1; - - }); - - int result = combinedFuture.join(); // 결과 가져오기 - System.out.println("최종 결과: " + result); - } + public static void main(String[] args) { + CompletableFuture cf = new CompletableFuture<>(); + + new Thread(() -> { + try { + Thread.sleep(2000); + + cf.completeExceptionally(new RuntimeException("비동기 작업 중 오류 발생")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + + new Thread(() -> { + while (!cf.isDone()) { + System.out.println("작업 진행 중..."); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + if (cf.isCompletedExceptionally()) { + System.out.println("작업이 예외처리 되었습니다."); + } else { + System.out.println("작업이 정상적으로 완료되었습니다."); + } + }).start(); + + try { + String result = cf.get(); + + System.out.println("비동기 작업 결과: " + result); + } catch (ExecutionException e) { + System.out.println("예외 발생: " + e.getCause().getMessage()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/io/concurrency/chapter11/exam10/isDoneExample.java b/src/main/java/io/concurrency/chapter11/exam10/isDoneExample.java index 5ce2b34..0d60b55 100644 --- a/src/main/java/io/concurrency/chapter11/exam10/isDoneExample.java +++ b/src/main/java/io/concurrency/chapter11/exam10/isDoneExample.java @@ -1,43 +1,44 @@ package io.concurrency.chapter11.exam10; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; public class isDoneExample { - public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { + public static void main(String[] args) { + CompletableFuture cf = new CompletableFuture<>(); - CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> { + new Thread(() -> { try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - return 42; - }); + Thread.sleep(2000); - CompletableFuture cf2 = cf1.thenApplyAsync(result -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - return result * 2; - }); - - while (!cf1.isDone() || !cf2.isDone()) { - System.out.println("작업이 아직 완료되지 않았습니다."); - try { - Thread.sleep(1000); + cf.complete("작업 완료!"); } catch (InterruptedException e) { e.printStackTrace(); } - } + }).start(); + + // 메인 스레드에서 완료 상태를 주기적으로 확인 + new Thread(() -> { + while (!cf.isDone()) { + System.out.println("작업 진행 중..."); + + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } - // 결과 가져오기 - int firstResult = cf1.get(); - int secondResult = cf2.get(); + System.out.println("작업이 완료되었습니다."); + }).start(); - System.out.println("첫 번째 결과: " + firstResult); - System.out.println("두 번째 결과: " + secondResult); + try { + String result = cf.get(); + + System.out.println("비동기 작업 결과: " + result); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/io/concurrency/chapter11/exam11/GetExample.java b/src/main/java/io/concurrency/chapter11/exam11/GetExample.java new file mode 100644 index 0000000..db53544 --- /dev/null +++ b/src/main/java/io/concurrency/chapter11/exam11/GetExample.java @@ -0,0 +1,33 @@ +package io.concurrency.chapter11.exam11; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class GetExample { + + public static void main(String[] args) { + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return "비동기 작업 처리!"; + }); + + try { + String result = future.get(3, TimeUnit.SECONDS); + + System.out.println("Result: " + result); + } catch (TimeoutException e) { + System.out.println("Timeout occurred before the task was completed"); + } catch (InterruptedException e) { + System.out.println("Thread was interrupted while waiting"); + } catch (ExecutionException e) { + System.out.println("Exception occurred during the computation: " + e.getCause()); + } + } +}