본문 바로가기
Java/study

스트림과 병렬처리

by avvin 2019. 4. 20.

병렬(parallel)처리 : 한 가지 작업을 서브 작업으로 나누고, 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는 것


스트림(Stream)


자바8부터 추가된 컬렉션(배열 포함)의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자


Stream의 foreach() 메서드는 Consumer 함수적 인터페이스 타입의 매개값을 가지므로 

컬렉션 요소를 소비할 코드를 람다식으로 가술할 수 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
 
public class Hello {
 
    public static void main(String[] args) {
 
        List<String> list = Arrays.asList("ㅇㅇㅇ""ㅁㅁㅁ""ㄴㄴㄴ");
        Stream<String> stream = list.stream();
 
        stream.forEach(name -> System.out.println(name));
 
    }
}
cs



Stream이 Iterator와 다른 점


1. 람다식으로 요소처리 코드 제공


2. 내부 반복자 사용으로 병렬처리가 쉬움 

외부반복자 : 개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드

내부반복자는 요소들을 분배시켜 병렬작업을 할 수 있게 도와준다.


(List<T> 메서드)

stream() : 순차처리 스트림

parallelStream() : 병렬처리 스트림


순차러리 스트림과 병렬처리 스트림을 이용할때 사용된 스레드의 이름이 무엇인지 콘솔에 출력해보기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package sec06.exam01;
 
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
 
public class Hello {
 
    public static void main(String[] args) {
 
        List<String> list = Arrays.asList("ㅇㅇㅇ""ㅁㅁㅁ""ㄴㄴㄴ");
 
        // 순차 처리
        Stream<String> stream = list.stream();
        stream.forEach(Hello::print);
 
        System.out.println();
 
        // 병렬 처리
        Stream<String> parallelStream = list.parallelStream();
        parallelStream.forEach(Hello::print);
 
    }
 
    public static void print(String str) {
        System.out.println(str + " : " + Thread.currentThread().getName());
    }
 
}
 
cs


출력결과


ㅇㅇㅇ : main

ㅁㅁㅁ : main

ㄴㄴㄴ : main


ㅁㅁㅁ : main

ㄴㄴㄴ : main

ㅇㅇㅇ : ForkJoinPool.commonPool-worker-2 // ForkJoinPool : '병렬 처리 (스트림과 병렬처리 뒷부분)'에서 다룬다.



ex)  순차처리 스트림은 하나의 스레드가 요소들을 순차적으로 읽어 합을 구하지만, 

병렬 처리 스트림을 이용하면 여러 개의 스레드가 요소들을 부분적으로 합하고 이 부분 합을 최종 결합해서 합을 생성한다.



3. 중간 처리와 최종 처리 가능


스트림은 컬렉션의 요소에 대해 중간 처리와 최종 처리를 수행할 수 있다.


중간 처리에서는 *매핑, 필터링, 정렬을 수행하고 // 리턴타입을 확인해보면 스트림 타입이다.

최종 처리에서는 반복, 카운팅, 평균, 총합 등의 집계 처리를 수행한다.


*매핑 (mapping)은 중간처리 기능으로, 스트림의 요소를 다른 요소로 대체하는 작업을 말한다.

스트림의 매핑 기능을 하는 메서드들은 새로운 스트림을 리턴하여 기존 스트림의 요소를 다른 요소로 대체하는 작업을 한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package sec06.exam01;
 
import java.util.Arrays;
import java.util.List;
 
public class Hello {
 
    public static void main(String[] args) {
 
        List<Student> studentList = Arrays.asList(
                new Student("ㅁㅁㅁ"80), 
                new Student("ㄴㄴㄴ"90),
                new Student("ㅇㅇㅇ"100));
 
        double average = studentList.stream()// 학생 객체로 이루어진 스트림
                // 학생 객체로 이루어진 스트림을 학생객체의 점수로 이루어진 스트림으로 대체(매핑)
                .mapToInt(Student::getScore) // 리턴 타입 :IntStream
 
                .average() // IntStream 인터페이스의 메서드 average()
                .getAsDouble();
        
        System.out.println(average);
 
    }
 
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package sec06.exam01;
 
public class Student {
 
    String name;
    int score;
 
    // 생성자
    public Student(String name, int score) {
 
        this.name = name;
        this.score = score;
 
    }
 
    public String getName() {
        return name;
    }
 
    public int getScore() {
        return score;
    }
 
}
 
cs


스트림의 중간처리 메서드들은 리턴타입이 스트림타입이라 스트림 메서드로 최종처리를 할 수 있게 해준다.
리턴타입이 기본 타입이거나 OptionalXXX라면 최종처리 메서드


스트림 파이프라인






(임시저장)


파일로부터 스트림 얻기 (p.793)


디렉토리로부터 스트림 얻기 (p.794)