반응형
Notice
Recent Posts
Recent Comments
관리 메뉴

간단한 개발관련 내용

[JAVA] Java 에서 Thread 를 다루는 기술들 정리 본문

Computer Science/Java

[JAVA] Java 에서 Thread 를 다루는 기술들 정리

vincenzo.dev.82 2024. 12. 31. 15:42
반응형

1. Native Threads (Java 1.0)

  • 등장 시기: Java 1.0 (1995년)
  • 기본 개념:
    • java.lang.Thread 클래스를 사용하여 직접 스레드를 생성하고 관리.
    • Runnable 인터페이스를 통해 스레드에서 실행할 코드를 정의.
    • 동기화(synchronized)와 wait()/notify() 메서드를 사용해 스레드 간 통신 및 동기화 구현.
  • 예제:
class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread is running...");
    }
}

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyTask());
        thread.start(); // 스레드 시작
    }
}

 


2. ThreadLocal (Java 1.2)

  • 등장 시기: Java 1.2 (1998년)
  • 기본 개념:
    • ThreadLocal은 스레드별로 독립적인 데이터를 저장하기 위한 클래스.
    • 여러 스레드가 동일한 객체를 공유하더라도 각 스레드가 자신의 값을 유지.
    • 동기화 없이 스레드 안전성을 보장.
  • 예제:
public class ThreadLocalExample {

    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            threadLocal.set(1);
            System.out.println(Thread.currentThread().getName() + " - Value: " + threadLocal.get());
        });

        Thread thread2 = new Thread(() -> {
            threadLocal.set(2);
            System.out.println(Thread.currentThread().getName() + " - Value: " + threadLocal.get());
        });

        thread1.start();
        thread2.start();
    }
}
  • 출력 예시:
Thread-0 - Value: 1
Thread-1 - Value: 2

 


3. Executors (Thread Pool, Java 1.5)

  • 등장 시기: Java 1.5 (2004년)
  • 기본 개념:
    • 스레드를 직접 생성하지 않고, **스레드 풀(Thread Pool)**에서 관리.
    • java.util.concurrent 패키지의 Executor 프레임워크를 통해 스레드 생성 및 관리를 단순화.
    • 재사용 가능한 스레드 풀을 제공해 성능 최적화.
  • 예제:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Runnable task1 = () -> System.out.println("Task 1 running");
        Runnable task2 = () -> System.out.println("Task 2 running");

        executor.submit(task1);
        executor.submit(task2);

        executor.shutdown(); // 스레드 풀 종료
    }
}

 


4. Locks and Conditions (Java 1.5)

  • 등장 시기: Java 1.5 (2004년)
  • 기본 개념:
    • 기존 synchronized 대신, java.util.concurrent.locks 패키지에 포함된 ReentrantLock 제공.
    • 더 세밀한 스레드 제어 가능.
    • 조건 변수(Condition)를 통해 특정 조건에서 스레드가 대기하고 신호를 기다리게 할 수 있음.
  • 예제:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    private final Lock lock = new ReentrantLock();

    public void criticalSection() {
        lock.lock();
        try {
            System.out.println("Critical section");
        } finally {
            lock.unlock();
        }
    }
}

 


5. Fork/Join Framework (Java 7)

  • 등장 시기: Java 7 (2011년)
  • 기본 개념:
    • 작업을 작은 작업으로 분할(분할 정복 알고리즘)한 뒤 병렬 실행.
    • ForkJoinPool 을 사용하여 작업들을 관리.
    • 큰 작업을 여러 작은 작업으로 나누고(fork()), 결과를 병합(join())하여 처리.
  • 예제:
import java.util.concurrent.RecursiveTask;

class SumTask extends RecursiveTask<Integer> {
    private final int[] arr;
    private final int start, end;

    public SumTask(int[] arr, int start, int end) {
        this.arr = arr;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if (end - start <= 10) {
            int sum = 0;
            for (int i = start; i < end; i++) {
                sum += arr[i];
            }
            return sum;
        }

        int mid = (start + end) / 2;
        SumTask leftTask = new SumTask(arr, start, mid);
        SumTask rightTask = new SumTask(arr, mid, end);

        leftTask.fork();
        int rightResult = rightTask.compute();
        int leftResult = leftTask.join();

        return leftResult + rightResult;
    }
}

 


6. Parallel Streams (Java 8)

  • 등장 시기: Java 8 (2014년)
  • 기본 개념:
    • Stream API와 병렬 처리를 통합.
    • 개발자는 병렬 처리를 명시적으로 구현할 필요 없이, **parallelStream()**을 사용해 병렬 처리를 수행.
  • 예제:
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        int sum = Arrays.stream(numbers)
                        .parallel()
                        .filter(n -> n % 2 == 0)
                        .sum();

        System.out.println("Sum of even numbers: " + sum);
    }
}

 


7. CompletableFuture (Java 8)

  • 등장 시기: Java 8 (2014년)
  • 기본 개념:
    • 비동기 작업을 단순화하기 위해 등장.
    • 콜백 스타일의 비동기 코드와 병렬 처리를 지원.
    • thenApply, thenAccept와 같은 체인 메서드를 통해 작업 흐름 관리.
  • 예제:
import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> "Hello")
                         .thenApply(s -> s + " World")
                         .thenAccept(System.out::println);
    }
}

 


8. Virtual Threads (Java 21)

  • 등장 시기: Java 21 (2023년)
  • 기본 개념:
    • 기존의 OS 스레드와 달리, JVM에서 경량화된 가상 스레드 지원.
    • Thread.startVirtualThread()로 쉽게 사용 가능.
    • 기존의 스레드와 동일한 API를 제공하지만, 성능이 훨씬 향상.
  • 예제:
public class Main {
    public static void main(String[] args) {
        Thread.startVirtualThread(() -> System.out.println("Virtual thread running!"));
    }
}

정리

기술 버전 특징
Native Threads Java 1.0 Thread와 Runnable 기반, 직접 스레드 생성 및 관리
ThreadLocal Java 1.2 스레드별 독립적인 데이터 저장
Executors (Thread Pool) Java 1.5 스레드 풀 제공, 자원 재사용 가능
Locks and Conditions Java 1.5 ReentrantLock과 조건 변수 사용, 고급 동기화 지원
Fork/Join Framework Java 7 분할 정복 알고리즘 기반 병렬 처리
Parallel Streams Java 8 병렬 스트림을 통한 병렬 처리 지원
CompletableFuture Java 8 비동기 작업을 단순화, 콜백 스타일 지원
Virtual Threads Java 21 경량화된 가상 스레드, 높은 동시성 및 효율성 제공

 

반응형