[Java] Stream & Thread

배창민·2025년 9월 18일
post-thumbnail

Java Stream & Thread


1) Stream

1-1. Stream이란?

  • 컬렉션/배열의 요소를 선언형으로 순회·가공·축약하는 API (Java 8+).
  • 내부 반복자 기반 → 병렬 처리 용이.

1-2. 왜 필요한가?

  • for/iterator 대비 코드 간결, 조합 가능, 병렬 스트림으로 성능 향상 여지.

1-3. 특징

  1. 원본 불변(읽기 전용)
  2. 1회성(필요 시 재생성)
  3. 지연 연산(최종 연산 전까지 실행 X)
  4. **parallelStream()**로 병렬화 가능

2) Stream 활용

파이프라인 3단계

생성 → (가공: filter/map/… ) → 결과(collect/reduce/…)

2-1. 생성

// 배열
String[] arr = {"hello","stream","world"};
Arrays.stream(arr);                 // 전체
Arrays.stream(arr, 0, 2);           // 부분

// 컬렉션
List<String> list = List.of("hello","stream","world");
list.stream();                      // 순차
list.parallelStream();              // 병렬

// 빈 스트림
Stream<String> s = list == null || list.isEmpty() ? Stream.empty() : list.stream();

// builder
Stream<String> b = Stream.<String>builder().add("hello").add("stream").add("world").build();

// iterate (수열)
Stream<Integer> it = Stream.iterate(10, x -> x * 2).limit(5); // 10 20 40 80 160

// 기본 타입 (오토박싱 비용↓)
IntStream.range(5, 10);            // 5..9
LongStream.rangeClosed(1, 3);      // 1..3
new Random().doubles(5).boxed();   // Double 스트림 박싱

// 문자 관련
"Hello Stream".chars();                             // IntStream (code point)
Pattern.compile(",").splitAsStream("A,B,C");        // Stream<String>

// 합치기
Stream.concat(Stream.of("A","B"), Stream.of("C","D"));

2-2. 가공(중간연산)

역할메소드
필터링filter(Predicate) · distinct()
변환map(Function) · flatMap(Function<…Stream…>)
제한limit(n) · skip(n)
정렬sorted() · sorted(Comparator)
확인peek(Consumer)
// filter
IntStream.range(0,10).filter(i -> i % 2 == 0).forEach(System.out::print); // 02468

// map
IntStream.range(1,10).filter(i -> i%2==0).map(i -> i*5).forEach(System.out::print); // 10203040

// flatMap (중첩 → 평탄화)
List<List<String>> nested = List.of(List.of("JAVA","SPRING"), List.of("java","spring"));
List<String> flat = nested.stream().flatMap(Collection::stream).toList();

// sorted
List<Integer> sorted = IntStream.of(5,10,99,2,1).boxed().sorted().toList(); // [1,2,5,10,99]

2-3. 결과(최종연산)

(1) 계산

long cnt = IntStream.range(1,10).count();
long sum = IntStream.range(1,10).sum();
OptionalInt max = IntStream.range(1,10).max();
int oddSum = IntStream.range(1,10).filter(i -> i%2==1).sum();

(2) 축약 reduce

OptionalInt r1 = IntStream.range(1,4).reduce((a,b)->a+b);      // 1+2+3
int r2 = IntStream.range(1,4).reduce(100, Integer::sum);       // 100+(1+2+3)
int r3 = Stream.of(1,2,3).reduce(100, Integer::sum, Integer::sum);

(3) 수집 collect

record Member(String id, String name) {}
List<Member> members = List.of(
  new Member("t1","n1"), new Member("t2","n2"), new Member("t3","n3")
);

// toList
List<String> names = members.stream().map(Member::name).toList();

// joining
String joined = members.stream().map(Member::name).collect(Collectors.joining(" || ", "**", "**"));
// **n1 || n2 || n3**

(4) 매칭 any/all/noneMatch

List<String> s = List.of("Java","Spring","SpringBoot");
boolean any  = s.stream().anyMatch(v -> v.contains("p"));
boolean all  = s.stream().allMatch(v -> v.length() > 4);
boolean none = s.stream().noneMatch(v -> v.contains("c"));

3) Thread

3-1. 기본 개념

  • 프로세스: 실행 중인 프로그램(독립 자원/메모리 보유)
  • 스레드: 프로세스 내 실행 흐름 단위(자원 공유, 생성·전환 비용↓)

3-2. 멀티 프로세스 vs 멀티 스레드

  • 멀티 프로세스: 격리·안정성↑, 통신비용↑
  • 멀티 스레드: 자원 공유로 응답성↑, 동기화/교착상태 주의

3-3. 메인/데몬/종료

  • Java 프로그램은 main 스레드부터 시작
  • 데몬 스레드: 보조 작업(예: GC, 자동저장). 비데몬 모두 종료 시 강제 종료
  • 멀티 스레드 프로세스는 활성 스레드가 남아있으면 종료되지 않음

4) 스레드 생성·실행

4-1. 두 가지 방법

(A) Thread 상속

class MyThread extends Thread {
  @Override public void run() { /* 작업코드 */ }
}
new MyThread().start();  // 반드시 start()로 실행 (run() 직접호출 X)

(B) Runnable 구현

class MyTask implements Runnable {
  @Override public void run() { /* 작업코드 */ }
}
new Thread(new MyTask()).start();

차이: Thread 상속은 클래스 상속 점유, Runnable은 구성(Composition)으로 유연.

4-2. run vs start

  • run()일반 메소드 호출(동기 실행)
  • start()새 스레드 생성 → run() 실행 (진짜 병렬성)

5) 스케줄링

  • 우선순위(Priority): 1~10 (기본 5) — 높을수록 기회↑

    Thread t = new Thread(...);
    t.setPriority(Thread.MAX_PRIORITY);
  • 라운드로빈: 타임 슬라이스 기반 순환. JVM/OS 정책(코드로 제어 X)


6) 스레드 컨트롤 & 동기화

6-1. 주요 메소드 요약

메소드설명
sleep(ms)현재 스레드 잠시 멈춤
join()다른 스레드 종료까지 대기
interrupt()차단/대기 중 스레드 깨움(인터럽트 플래그)
yield()실행 양보(스케줄러 힌트)
wait()동기화 블록 내에서 대기(모니터 릴리즈)
notify() / notifyAll()대기중 스레드 하나/전체 깨움

6-2. 동기화(Synchronized)

  • 공유 자원 보호(원자성/가시성 보장). 한 시점 한 스레드만 진입.
// 메소드 전체 동기화
public synchronized void method() { /* 임계구역 */ }

// 블록 동기화
public void method1() {
  // ...
  synchronized (lock) { /* 임계구역 */ }
  // ...
}

핵심 요약

  • 스트림: 불변 + 지연 + 조합 + (필요 시) 병렬. map/filter → collect/reduce.
  • flatMap중첩 평탄화, Collectors.joining은 문자열 결합 치트키.
  • 스레드: start() 필수, 공유자원은 synchronized/wait/notify 패턴으로 보호.
  • 스케줄링·우선순위는 힌트일 뿐, 정확한 실행 순서는 보장되지 않음.
profile
개발자 희망자

0개의 댓글