고양이 여름이의 지식채널

JAVA 쓰레드(Thread) 프로그래밍 - 쓰레드 로컬과 ConcurrentHashMap 그리고 CompletableFuture 본문

Programming/JAVA

JAVA 쓰레드(Thread) 프로그래밍 - 쓰레드 로컬과 ConcurrentHashMap 그리고 CompletableFuture

썸머캣 2023. 3. 27. 23:01

자바 쓰레드 프로그래밍으로 쓰레드 로컬(ThreadLocal), ConcurrentHashMap 그리고 CompletableFuture 에 대해서 알아봅니다.


 

쓰레드 로컬 (ThreadLocal)

쓰레드 로컬은 쓰레드 간에 데이터를 공유할 수 있도록 돕는 자바의 클래스입니다. 이를 사용하면, 하나의 쓰레드에서 생성한 데이터를 다른 쓰레드에서도 사용할 수 있게 됩니다. 이를 통해 쓰레드 간 데이터 공유를 보다 안전하게 처리할 수 있습니다.

public class ThreadLocalExample {

  // ThreadLocal 객체 생성
  public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();

  public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(() -> {
      // 현재 쓰레드에서 THREAD_LOCAL 객체에 데이터를 저장
      THREAD_LOCAL.set("Thread 1 Data");
      
      // 현재 쓰레드에서 THREAD_LOCAL 객체에 저장된 데이터 출력
      System.out.println(Thread.currentThread().getName() + ": " + THREAD_LOCAL.get());
    });

    Thread thread2 = new Thread(() -> {
      // 현재 쓰레드에서 THREAD_LOCAL 객체에 데이터를 저장
      THREAD_LOCAL.set("Thread 2 Data");
      
      // 현재 쓰레드에서 THREAD_LOCAL 객체에 저장된 데이터 출력
      System.out.println(Thread.currentThread().getName() + ": " + THREAD_LOCAL.get());
    });

    thread1.start(); // 쓰레드 1 시작
    thread2.start(); // 쓰레드 2 시작

    thread1.join(); // 쓰레드 1이 종료될 때까지 기다림
    thread2.join(); // 쓰레드 2이 종료될 때까지 기다림

	// 메인 쓰레드에서 THREAD_LOCAL 객체에 저장된 데이터 출력
    System.out.println("Main Thread: " + THREAD_LOCAL.get());
  }
}

쓰레드 로컬을 사용하여 각 쓰레드에서 데이터를 저장하고 출력하는 방법입니다.

THREAD_LOCAL이라는 이름의 ThreadLocal 객체를 생성하고, 각 쓰레드에서 이를 이용하여 데이터를 저장하고 출력합니다. 
thread1에서는 THREAD_LOCAL에 "Thread 1 Data"라는 데이터를 저장하고 출력하고, thread2에서는 THREAD_LOCAL에 "Thread 2 Data"라는 데이터를 저장하고 출력합니다. 그리고 마지막으로 main 메서드에서는 THREAD_LOCAL에 저장된 데이터를 출력합니다. 이렇게 되면, 각 쓰레드에서는 자신만의 데이터를 저장하고, 다른 쓰레드와 공유하지 않으며, 메인 쓰레드에서는 이전에 저장된 데이터를 가져올 수 없습니다. 이렇게 ThreadLocal을 사용하면 쓰레드 간 데이터 공유를 안전하게 할 수 있습니다.

 

ConcurrentHashMap

ConcurrentHashMap은 HashMap과 비슷한 구조를 가지고 있지만, 여러 쓰레드가 동시에 접근하더라도 안전하게 사용할 수 있는 자료구조입니다. 이를 가능하게 하는 것은 내부적으로 세분화된 로직을 사용하여 쓰레드 간에 충돌이 발생하지 않도록 보장하는 것입니다.

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
  public static void main(String[] args) {
    ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // ConcurrentHashMap 객체 생성 및 초기 데이터 삽입
    map.put("apple", 1);
    map.put("banana", 2);
    map.put("orange", 3);

    Thread thread1 = new Thread(() -> {
      map.put("apple", 4); // 쓰레드1에서 apple 데이터 갱신
      System.out.println("Thread 1: apple value = " + map.get("apple")); // 쓰레드1에서 갱신된 apple 데이터 출력
    });

    Thread thread2 = new Thread(() -> {
      map.put("banana", 5); // 쓰레드2에서 banana 데이터 갱신
      System.out.println("Thread 2: banana value = " + map.get("banana")); // 쓰레드2에서 갱신된 banana 데이터 출력
    });

    thread1.start(); // 쓰레드1 시작
    thread2.start(); // 쓰레드2 시작

    try {
      thread1.join(); // 쓰레드1이 종료될 때까지 대기
      thread2.join(); // 쓰레드2이 종료될 때까지 대기
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("Main thread: map = " + map); // 메인 쓰레드에서 전체 데이터 출력
  }
}

ConcurrentHashMap을 사용하여 멀티쓰레드 환경에서 안전하게 데이터를 관리하는 방법입니다.

ConcurrentHashMap 객체를 생성하고 초기 데이터를 삽입한 뒤, 두 개의 쓰레드에서 각각 데이터를 갱신하고 출력합니다. thread1에서는 apple 데이터를 갱신하고 출력하고, thread2에서는 banana 데이터를 갱신하고 출력합니다. 각 쓰레드에서는 ConcurrentHashMap이 제공하는 안전한 데이터 갱신 메서드를 사용하여 데이터를 갱신합니다. 마지막으로, 메인 쓰레드에서는 전체 데이터를 출력합니다. ConcurrentHashMap을 사용하면 멀티쓰레드 환경에서 안전하게 데이터를 관리할 수 있습니다.

 

 

반응형

 

CompletableFuture

CompletableFuture는 자바 8에서 도입된 비동기 작업 처리를 위한 클래스입니다. CompletableFuture는 내부적으로 쓰레드 풀을 사용하며 이 클래스를 사용하면, 쓰레드를 블록하지 않고 비동기 작업을 처리할 수 있습니다. 이를 통해 더욱 효율적으로 작업을 처리할 수 있습니다.

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
  public static void main(String[] args) {
    CompletableFuture.supplyAsync(() -> "Hello") // supplyAsync() 메서드를 이용하여 새로운 쓰레드에서 비동기 작업 실행
      .thenApplyAsync(s -> s + " World") // thenApplyAsync() 메서드를 이용하여 이전 작업 결과를 가지고 다음 작업 실행
      .thenAcceptAsync(System.out::println) // thenAcceptAsync() 메서드를 이용하여 최종 결과 처리
      .join(); // 모든 작업이 완료될 때까지 대기
  }
}

CompletableFuture를 사용하여 비동기 작업을 처리하는 방법입니다. 

supplyAsync() 메서드를 이용하여 새로운 쓰레드에서 "Hello"라는 문자열을 반환하는 작업을 실행하고, thenApplyAsync() 메서드를 이용하여 이전 작업 결과를 가지고 " World" 문자열을 추가하는 작업을 실행합니다.

그리고 마지막으로 thenAcceptAsync() 메서드를 이용하여 최종 결과를 출력하는 작업을 실행합니다. join() 메서드를 이용하여 모든 작업이 완료될 때까지 대기합니다. 이렇게 되면, 비동기 작업이 처리되면서 각 작업 결과가 연속적으로 처리되고, 최종 결과가 출력됩니다.

 


 

JAVA 쓰레드(Thread) 프로그래밍 - 쓰레드 풀과 데드락

 

JAVA 쓰레드(Thread) 프로그래밍 - 쓰레드 풀과 데드락

자바 쓰레드 프로그래밍으로 쓰레드풀과 데드락에 대해서 알아봅니다. 쓰레드 풀(Thread Pool) 쓰레드 풀은 쓰레드를 효율적으로 사용하기 위한 방법입니다. 여러 개의 쓰레드를 미리 만들어 놓고,

summer-cat93.tistory.com

 

 

728x90
반응형
Comments