// 에드센스


1. 객체 정렬?

class Person {
    String name;
    int weight;
    int height;

    public Person(String name, int height, int weight) {
        this.name = name;
        this.weight = weight;
        this.height = height;
    }

    public void print() {
        System.out.println(name + " " + height + " " + weight);
    }

    public int getWeight() {
        return weight;
    }

    public int getHeight() {
        return height;
    }
}

여기 Person 클래스가 있다.

 

 

List<Person> list = new ArrayList<>();

Person 클래스로 이루어진 어레이리스트도 있다.

 

이 리스트를 정렬하고하자한다.

name을 기준으로 정렬을 해야할까 weight를 기준으로 정렬을 해야할까?

우리는 이 문제를 Comparable이나 Comparator를 통해서 해결할 수 있다.

 

 

 

 


1. Comparable

정렬하고자 하는 객체의 클래스에 Comparable 인터페이스를 구현하는 방법이다.

물론 그 클래스에 Comparable 인터페이스를 구현할 수 있다면 말이다.

// 정렬 대상 클레스에 인터페이스를 구현할 수 있다면 Comparable 사용 가능
class Person implements Comparable<Person> {
    String name;
    int weight;
    int height;

    public Person(String name, int height, int weight) {
        this.name = name;
        this.weight = weight;
        this.height = height;
    }

    public void print() {
        System.out.println(name + " " + height + " " + weight);
    }

    public int getWeight() {
        return weight;
    }

    public int getHeight() {
        return height;
    }

    @Override
    public int compareTo(Person p) {
        // 오름차순: this 객체 - 인자로 넘어온 객체
        // 내림차순: 인자로 넘어온 객체 - this 객체
        return this.height - p.height; // 오름차순 정렬
    }
}
Collections.sort(list);

Comparable 인터페이스의 compareTo 메소드를 구현하면 된다.

위 코드는 height를 기준으로 오름차순 정렬의 예시다.

 

 

 

만약 1순위로 height를 기준으로 오름차순 정렬하고

height가 같은 객체가 있다면

2순위로 weight를 기준으로 내림차순 정렬하고 싶다면?

 

class Person implements Comparable<Person> {
    String name;
    int weight;
    int height;

    public Person(String name, int height, int weight) {
        this.name = name;
        this.weight = weight;
        this.height = height;
    }

    public void print() {
        System.out.println(name + " " + height + " " + weight);
    }

    public int getWeight() {
        return weight;
    }

    public int getHeight() {
        return height;
    }

    @Override
    public int compareTo(Person p) {
        // this 객체 > 인자로 넘어온 객체 => return 1이라는것은
        // this 객체 - 인자로 넘어온 객체 > 0 => 오름차순
        if (this.height > p.height) return 1;
        else if (this.height == p.height) { // height가 같다면
            // this 객체 < 인자로 넘어온 객체 => return 1이라면
            // this 객체 - 인자로 넘어온 객체 < 0 => 내림차순
            if (this.weight < p.weight) return 1; // weight를 내림차순으로
        }
        return -1;
    }
}

이렇게 하면 된다.

 

 

 

 


2. Comparator

정렬하고자 하는 객체의 클래스에 Comparable 인터페이스를 구현할 수 없을때 사용하는 방법이다.

혹은 Comprable 인터페이스를 통해 이미 정렬기준이 정해져있지만 다른 기준으로 정렬하고 싶을때 사용하는 방법이다.

 

// 정렬 대상 클레스에 인터페이스를 구현할 수 없다면
// 혹은 Comparable을 통해 이미 정해져있는 정렬 기준과 다르게 정렬하고 싶다면
class Person {
    String name;
    int weight;
    int height;

    public Person(String name, int height, int weight) {
        this.name = name;
        this.weight = weight;
        this.height = height;
    }

    public void print() {
        System.out.println(name + " " + height + " " + weight);
    }

    public int getWeight() {
        return weight;
    }

    public int getHeight() {
        return height;
    }
}

Person 클래스는 동일하다.

 

 

 

우리는 Comparator라는 일종의 정렬기준을 정의한 객체를 만들어서 Collections.sort()의 인자로 넣어주어야 한다.

 

    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

 

Collections.sort 함수를 까보면 첫번째로 정렬 할 리스트와 두번째로 정렬 기준인 Comparator를 받는 것을 볼 수 있다.

 

 

 

Collections.sort(list, new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
    	// 오름차순
        return o1.height - o2.height;
    }
});

 

Comparator객체를 한번쓰고 버릴것 이니 익명클래스로 넣어주었다.

저 익명클래스의 객체는 Comparator 인터페이스를 구현받고있기에 compare 함수를 오버라이드하고있다.

 

 

 

정렬 기준이 2개 이상일 때도 Comparable과 동일하게 해주면 된다.

Collections.sort(list, new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
    	// height 기준 오름차순
        if (o1.height > o2.height) return 1;
        else if (o1.height == o2.height) {
        	// height가 같다면 weight 기준으로 내림차순
            if (o1.weight < o2.weight) return 1;
        }
        return -1;
    }
});

 

 

 

Comparator를 람다함수로 조금더 간단하게 표현할 수 있다.

Collections.sort(list, (a, b) -> a.getHeight() - b.getHeight());

 

 

 

stream을 쓰면 더더더 간단하게 표현할 수 있다.

list.sort(Comparator.comparing(Person::getHeight));

 

 

 

stream을 사용했을때 2개 이상의 기준을 적용하고 싶다면

list.sort(Comparator.comparing(Person::getHeight).thenComparing(Person::getWeight));

 

이렇게 thenComparing을 통해 이어주면 된다.

하나의 조건은 역순으로 하고싶다면 .reversed()를 붙혀주면 되는데 주의 할 것이

 

 

 

list.sort(Comparator.comparing(Person::getHeight).thenComparing(Person::getWeight).reversed());

 

이렇게 뒤에 reversed()를 바로 붙이면 height에 대한 정렬도 reversed()에 영향을 받아서 두가지 기준 다 내림차순 정렬이 돼 버린다.

 

 

 

두번째 기준만 내림차순으로 하고 싶다면

Comparator<Person> reverseCompare = Comparator.comparing(Person::getWeight).reversed();
list.sort(Comparator.comparing(Person::getHeight).thenComparing(reverseCompare));

 

이렇게 reverse용 Comparator를 따로 만들어서 넣어주어야 한다.

 

 

 

 

참고:

 

'Java' 카테고리의 다른 글

[Java] 해시/해시테이블이란?  (0) 2021.07.12
[Java] 제네릭(Generic)  (0) 2021.07.11
[Java] Garbage Collection  (4) 2021.07.01
[Java] Thread/MultiThread 4 - 동시성 문제  (0) 2021.06.29
[Java] Static 키워드  (0) 2021.06.28

사실 자료구조 카테고리에 맞는 게시글이지만 아직 자료구조 카테고리가 없고 앞으로 딱히 만들 계획이 없기에, 그리고 구현을 자바로 했기에 자바 카테고리에 넣었다! 그냥 그런걸로 하자 ㅎㅎ

 

해시란?

해쉬브라운

  • 해시란 임의의 크기를 가진 데이터를 고정된 크기의 데이터로 변화시켜 저장하는것이다. 이 과정은 해시함수를 통해 진행되며 해시값 자체를 index로 사용하기에 평균 시간복잡도가 O(1)으로 매우 빠르다
  • 키(key) 1개와 값(value) 1개가 1:1로 연관되어 있는 자료구조이다. 따라서 키(key)를 이용하여 값(value)을 도출할 수 있다.
    이 그럼처럼 John Smith라는 이름과 전화번호가 매핑이 되어있고 전화번호를 찾기위해선 John Smith라는 이름을 해시함수를 통해 변환한 해시코드를 통해 찾을 수 있다. 

 

 

해시함수와 충돌

key를 해시함수를 통해서 해시코드로 변환시키고 이 해시코드를 인덱스로 사용하여 value를 저장하는데, 이때 충돌(Collision)이 발생할 수 있다. 다음의 예시를 보자

John Smith와 Sandra Dee라는 key가 해시함수를 통해 해시코드로 변환되었는데 우연히 같은 코드로 변환된 것이다. 

 

즉, 무한한 값(KEY)을 유한한 값(HashCode)으로 표현하면서

서로 다른 두 개 이상의 유한한 값이 동일한 출력 값을 가지게 된다는 것이다.

 

key가 될 수 있는 경우는 무한하고 해시테이블은 유한하니 소위 비둘기집 원리라고 부르는 문제가 발생한다. 이런 문제로 인해 우리는 해시함수의 중요성을 느낄 수 있다. 최대한 겹치지 않고 다양한 값을 보장하는 해시 함수라면 이런 문제를 조금 개선할 수 있지만 그래도 근본적으로는 불가능하다. 따라서 우리는 다른 개선방법을 사용한다. 크게 두가지의 해결 방법이 있는데 Separate Chaining기법과 Open Addressing(개방 주소법)이 있다.

 

 

충돌 해결1. Separate Chaining(Chaining) 기법

John Smith가 들어가 있는데 그 공간에 또 Sandra Dee가 들어갈때 Collision이 발생한다. 이때 Sandra의 value를 기존 John의 뒤에 체인처럼 이어 붙혀준다. 152번지에 John과 Sandra의 정보가 함께 존재하도록 한것이다.

 

장점

  • 한정된 저장 공간을 효율적으로 사용할 수 있다.
  • 해시 함수에 대한 의존성이 상대적으로 적다.
  • 메모리 공간을 미리 잡아 놓을 필요가 없다.(그때그때 이어 붙이기 때문)

단점

  • 한 hash에만 자료가 계속 들어간다면(쏠린다면) 검색 효율이 떨어진다(.최악의 경우 O(n))
  • 외부 저장공간을 사용한다.

 

 

충돌 해결2. Open Addressing(개방주소법)

개방주소법은 데이터의 해시(hash)가 변경되지 않았던 chaining과는 달리 비어있는 해시(hash)를 찾아 데이터를 저장하는 기법이다. 따라서 개방주소법에서의 해시테이블은 1개의 해시와 1개의 값(value)가 매칭되어 있는 형태로 유지된다.

 

 

장점

  • 추가 저장공간이 필요없다

단점

  • 해시 함수의 성능에 전체 해시테이블의 성능이 좌지우지 된다.
  • 데이터의 길이가 늘어나면 그에 해당하는 저장소를 마련해 두어야한다.

 

 

 

Chaining 기법을 사용한 해시테이블 구현

HashTable 클래스

import java.util.LinkedList;

public class HashTable {
	class Node{
		String key;
		String value;
		public Node(String key, String value) {
			this.key = key;
			this.value = value;
		}
		
		String getValue() {
			return value;
		}
		
		void setValue(String value) {
			this.value = value;
		}
	}
	
	//각 배열 칸에 링크드리스트를 넣음으로서 collision이 발생할 시 뒤에 이어나간다.
	LinkedList<Node>[] data;
	
	//해시테이블을 생성하는 순간 생성자를 통해서 배열 크기 초기화
	HashTable(int size){
		this.data = new LinkedList[size];
	}
	
	//키를 해쉬코드로 변환하는 메소드
	int getHashCode(String key) {
		int hashcode = 0;
		for(char c : key.toCharArray()) {
			hashcode += c;
		}
		return hashcode;
	}
	
	//해쉬코드를 배열의 인덱스로 변환하는 메소드
	int convertHashCodeToIndex(int hashcode) {
		return hashcode % data.length;
	}
	
	//배열의 인덱스에 노드가 여러개 있다면 key를 통해 알맞은 value를 찾는 메소드
	Node searchKey(LinkedList<Node> list , String key) {
		//리스트에 아무것도 없으면 null 반환
		if(list == null) {
			 return null;
		}
		
		//리스트에 있는 노드중에 찾는 key를 가진 노드가 있다면 반환
		for(Node node : list) {
			if(node.key.equals(key)) {
				return node;
			}
		}
		
		//리스트에 노드가 없다면 null 반환
		return null;
	}
	
	//key-value를 저장하는 메소드
	void put(String key, String value) {
		int hashcode = getHashCode(key);
		int index = convertHashCodeToIndex(hashcode);
		
		//배열의 해당 인덱스에 들어가있던 리스트 가져온다
		LinkedList<Node> list = data[index];
		
		//배열의 해당 인덱스 번지에 아직 리스트가 없다면
		if(list == null) {
			//리스트 만들고 해당 인덱스에 넣는다
			list = new LinkedList<Node>();
			data[index] = list;
		}
		
		//가져온 리스트에 지금 넣고자하는 key가 먼저 들어가있는지 확인
		Node node = searchKey(list, key);
		
		//노드가 없다면 처음 들어가는 key라는 의미
		if(node == null) {
			list.addLast(new Node(key, value));
		}
		else {
			//이미 해당 key로 들어가있는 노드가 있다면 지금 넣는 key로 덮어쓰기
			node.value = value;
		}
	}
	
	//key를 통해 value 가져오는 메소드
	String get(String key) {
		int hashcode = getHashCode(key);
		int index = convertHashCodeToIndex(hashcode);
		LinkedList<Node> list = data[index];
		
		//해당 인덱스에 있는 list에서 key를 통해 value를 찾는다
		Node node = searchKey(list, key);
		
		//해당 key값의 node가 없으면 Not Found반환, 있으면 value 반환
		return node == null ? "Not Found" : node.value;
	}
}

 

HashTest 클래스

public class HashTest {

	public static void main(String[] args) {
		
		//크기 3의 해쉬테이블 생성
		HashTable ht = new HashTable(3);
		
		ht.put("Lee", "lee is pretty");
		ht.put("Kim", "kim is smart");
		ht.put("Hee", "hee is an angel");
		ht.put("Choi", "choi is cute");
		
		//존재하는 데이터 검색
		System.out.println(ht.get("Lee"));
		System.out.println(ht.get("Kim"));
		System.out.println(ht.get("Hee"));
		System.out.println(ht.get("Choi"));

		//존재하지 않는 데이터 검색
		System.out.println(ht.get("Kang"));
		
		//기존 데이터 덮어쓰기
		ht.put("Choi", "choi is sexy");
		System.out.println(ht.get("Choi"));
	}
}

 

 

데이터는 Node라는 클래스 형태로 저장된다. Node는 key와 value를 가지고 있고 Value의 getter와 setter가 있다.

class Node{
		String key;
		String value;
		public Node(String key, String value) {
			this.key = key;
			this.value = value;
		}
		
		String getValue() {
			return value;
		}
		
		void setValue(String value) {
			this.value = value;
		}
	}

 

 

해시테이블은 배열로 선언하였고 각 칸마다 LinkedList<Node>형으로 선언하여 chaining 기법을 통한 Collision 회피 기법을 선택하였다.

	//각 배열 칸에 링크드리스트를 넣음으로서 collision이 발생할 시 뒤에 이어나간다.
	LinkedList<Node>[] data;

 

 

해시함수는 key의 각 문자들을 유니코드로 반환하여 모두 더하는 방식으로 구성했다. 

인덱스는 해시코드를 해시테이블의 사이즈로 나눈 나머지 값을 사용했다.

	//키를 해쉬코드로 변환하는 메소드
	int getHashCode(String key) {
		int hashcode = 0;
		for(char c : key.toCharArray()) {
			hashcode += c;
		}
		return hashcode;
	}
	
	//해쉬코드를 배열의 인덱스로 변환하는 메소드
	int convertHashCodeToIndex(int hashcode) {
		return hashcode % data.length;
	}

 

 

 

조회를 희망하는 key를 받아서 value를 찾는 메소드이다. key를 받아서 해시함수로 변환 후 인덱스로 변환하여 해당 인덱스에 존재하는 list를 가져온다. 그 리스트에서 우리가 입력한 key를 가진 Node를 찾는 searchKey 메소드를 통해 목적 Node를 찾아낸다.

	//key를 통해 value 가져오는 메소드
	String get(String key) {
		int hashcode = getHashCode(key);
		int index = convertHashCodeToIndex(hashcode);
		LinkedList<Node> list = data[index];
		
		//해당 인덱스에 있는 list에서 key를 통해 value를 찾는다
		Node node = searchKey(list, key);
		
		//해당 key값의 node가 없으면 Not Found반환, 있으면 value 반환
		return node == null ? "Not Found" : node.value;
	}

 

 

searchKey 메소드에서는 우리가 입력한 key를 가진 Node가 존재하는지 확인한다.

	//배열의 인덱스에 노드가 여러개 있다면 key를 통해 알맞은 value를 찾는 메소드
	Node searchKey(LinkedList<Node> list , String key) {
		//리스트에 아무것도 없으면 null 반환
		if(list == null) {
			 return null;
		}
		
		//리스트에 있는 노드중에 찾는 key를 가진 노드가 있다면 반환
		for(Node node : list) {
			if(node.key.equals(key)) {
				return node;
			}
		}
		
		//리스트에 노드가 없다면 null 반환
		return null;
	}

 

 

해시테이블에 데이터를 넣는 메소드로 chaining 기법을 구현했다. 중복되는 key가 이미 존재할 경우 해당 key에대한 value를 덮어쓰는 것으로 구현했다.

	//key-value를 저장하는 메소드
	void put(String key, String value) {
		int hashcode = getHashCode(key);
		int index = convertHashCodeToIndex(hashcode);
		
		//배열의 해당 인덱스에 들어가있던 리스트 가져온다
		LinkedList<Node> list = data[index];
		
		//배열의 해당 인덱스 번지에 아직 리스트가 없다면
		if(list == null) {
			//리스트 만들고 해당 인덱스에 넣는다
			list = new LinkedList<Node>();
			data[index] = list;
		}
		
		//가져온 리스트에 지금 넣고자하는 key가 먼저 들어가있는지 확인
		Node node = searchKey(list, key);
		
		//노드가 없다면 처음 들어가는 key라는 의미
		if(node == null) {
			list.addLast(new Node(key, value));
		}
		else {
			//이미 해당 key로 들어가있는 노드가 있다면 지금 넣는 key로 덮어쓰기
			node.value = value;
		}
	}

 

 

 

참고:

 

'Java' 카테고리의 다른 글

[Java] Comparable과 Comparator로 객체 정렬하기  (1) 2022.09.12
[Java] 제네릭(Generic)  (0) 2021.07.11
[Java] Garbage Collection  (4) 2021.07.01
[Java] Thread/MultiThread 4 - 동시성 문제  (0) 2021.06.29
[Java] Static 키워드  (0) 2021.06.28

정처기 벼락치기하느라 며칠 못올렸다.. 결과는 아직 모르겠다. 너무 간당간당 ㅠㅠ

암튼 이제 다시 한개씩 해보자 후. 오늘은 제네릭에 대한 개념 정리를 해보겠다.

 

제네릭이란?

"제네릭(Generic)은 클래스 내부에서 지정하는 것이 아닌

외부에서 사용자에 의해 지정되는 것을 의미"

 

한 줄 요약하면 위와 같다. 말하자면 타입을 매개변수로 넣어주는 그런 느낌.

class Person<T>{
    public T info;
}
 
public class GenericDemo {
 
    public static void main(String[] args) {
        Person<String> p1 = new Person<String>();
        Person<Integer> p2 = new Person<Integer>();
    }
 
}

Person 클래스를 생성할때 <여기>에 타입을 지정해주면 제네릭 변수 T를 통해서 info의 타입이 정해진다. T라는 문자 말고 다른 문자를 써도 되지만 암묵적인 룰이 있다.

타입 설명
<T> Type
<E> Element
<K> Key
<V> Value
<N> Number

 

그러면 이걸 왜 쓰는 것이고 쓰면 뭐가 좋은지 예제를 통해 탐구해보자.

 

 

 

제네릭을 쓰면 좋은점

타입안정성을 확보하고 중복을 줄일 수 있다.

먼저 다음의 중복이 있는 코드를 보자

class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}
class StudentPerson{
    public StudentInfo info;
    StudentPerson(StudentInfo info){ this.info = info; }
}
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class EmployeePerson{
    public EmployeeInfo info;
    EmployeePerson(EmployeeInfo info){ this.info = info; }
}

public class WithoutGeneric {
	public static void main(String[] args) {
	StudentInfo si = new StudentInfo(2);
        StudentPerson sp = new StudentPerson(si);
        System.out.println(sp.info.grade); 			// 2
        EmployeeInfo ei = new EmployeeInfo(1);
        EmployeePerson ep = new EmployeePerson(ei);
        System.out.println(ep.info.rank); 			// 1
	}
}

타입안정성이 확보된 코드이지만, StudentPerson 클래스와 EmployeePerson에서 중복이 발생했다. 같은 목적의 클래스이지만 타입이 다르기에 두번 쓴것인데 이를 개선하고자 이 두 클래스를 Person이라는 하나의 클래스로 통일해보자.

 

 

class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person{
    public Object info;
    Person(Object info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person p1 = new Person("부장");
        EmployeeInfo ei = (EmployeeInfo)p1.info;
        System.out.println(ei.rank);
    }
}

모든 타입을 받을 수 있는 Object형으로 info를 선언함으로 중복을 줄였다. 

그리고 EmployeeInfo ei = (EmployeeInfo)p1.info 으로 EmployeeInfo의 객체를 생성하려고 했다. 이때 컴파일에서 잡히지 않던 에러가 발생한다. 바로 EmployeeInfo의 멤버변수 rank는 int형인데 여기에 "부장"이라는 String을 넣으려고 한다는 에러다. 이번에는 중복을 줄였지만 타입안정성을 확보하지 못한 모습을 볼 수 있다.

 

이제 제네릭을 적용해서 중복과 타입 안정성을 모두 챙겨보자.

class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T>{
    public T info;
    Person(T info){ this.info = info; }
}

public class WithGeneric {

	public static void main(String[] args) {
	Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
        EmployeeInfo ei1 = p1.info;
        System.out.println(ei1.rank); // 성공
         
        Person<String> p2 = new Person<String>("부장");
        String ei2 = p2.info;
        System.out.println(ei2.rank); // 컴파일 실패
	}
}

이 경우에는 맨 마지막줄에서 빨간줄이 뜨면서 컴파일 에러가 발생한다. 즉 중요한것은

  • 런타임이 아닌 컴파일 단계에서 오류가 검출된다.
  • 중복의 제거와 타입 안정성을 동시에 추구할 수 있다.

 

 

제네릭의 특성

1. 복수의 제네릭도 가능하다

class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info; 
        this.id = id;
    }
}

 

2. 기본타입은 안되고 참조타입만 사용할 수 있다.

 

 

제네릭의 제한

제네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다.

abstract class Info{
    public abstract int getLevel();
}
class EmployeeInfo extends Info{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
    public int getLevel(){
        return this.rank;
    }
}
class Person<T extends Info>{
    public T info;
    Person(T info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person p1 = new Person(new EmployeeInfo(1));
        Person<String> p2 = new Person<String>("부장");
    }
}

class Person<T extends Info>를 보면 T타입은 Info클래스 자신이거나 이것을 상속받는 타입만 가능하다는 의미이다. 상속뿐 아니라 인터페이스의 implements도 가능하다. 반대로 부모타입만 가능하다는 의미의 super도 가능하다!

 

 

참고:

'Java' 카테고리의 다른 글

[Java] Comparable과 Comparator로 객체 정렬하기  (1) 2022.09.12
[Java] 해시/해시테이블이란?  (0) 2021.07.12
[Java] Garbage Collection  (4) 2021.07.01
[Java] Thread/MultiThread 4 - 동시성 문제  (0) 2021.06.29
[Java] Static 키워드  (0) 2021.06.28

프로그래밍을 하다보면 사용하지 않는 일명 "쓰레기"공간이 발생하여 프로그램의 성능을 저하시킨다. 자바에선 가비지 컬렉터가 이를 자동으로 탐지하여 해결해주는데 이 일을 해주는 가비지 컬렉터에 대해 알아보자. (이하 GC라고 하겠다.)

 

 

GC란

Person p1 = new Person("Kim");
Person p2 = new Person("Lee");

// p2가 가리키던 객체는 가비지가 된다.
p2 = p1;

 

 

Kim이라는 이름을 가진 p1 객체와 Lee라는 이름을 가진 p2객체가 있는데 p2라는 참조변수가 p1객체를 가리키게 한다면 원래 p2가 가리키던 Lee라는 객체는 더 이상 참조받을 수 없다. 즉 unreachable object가 되며 이를 가비지라고 한다. 

 

가비지 컬렉션이란

JVM의 힙영역에서 사용하지 않는 객체를 삭제하는 프로세스를 말한다.

 

 

GC는 Mark and sweep 알고리즘을 통해 동작한다.

  • mark는 reachable한 객체와 unreachable한 객체를 식별하는 과정
  • sweep은 식별한 unreachable객체를 제거하는 과정
  • compact과정도 추가되기도 한다. (메모리 단편화를 방지)

 

 

언제 동작하는가

GC도 결국엔 JVM에 올라가기 때문에 기본적으로 런타임에 동작한다.

가비지 컬렉션이 실행되기에는 몇 가지 조건이 있는데, 다음 조건 중 하나라도 충족되면 JVM은 GC를 실행한다.

 

  • OS로부터 할당 받은 시스템의 메모리가 부족한 경우
  • 관리하고 있는 힙에서 사용되는 메모리가 허용된 임계값을 초과하는 경우
  • 프로그래머가 직접 GC를 실행하는 경우(Java에서는 System.gc()라는 메소드가 있지만 가급적 안 쓰는 것이 좋다.)

 

 

JVM의 Heap 메모리 구조

이렇게 생겼다. 여기서 우리는 오른쪽의 Permanent영역을 제외한 부분만 살펴보자. 참고로 Young 영역에서 발생하는 GC를 Minor GC, Old영역의 GC는 Major GC라고 한다. Minor GC와 Major GC를 따로 만든 이유는 대부분의 객체는 금방 가비지가 된다는 가설을 전제로 하고 GC를 설계했기 때문이다.

Minor GC의 범위에서 사용되는 객체들(파란영역)이 훨씬 많은것을 알 수 있다.

 

Young Generation

GC를 이해하기 위해서 객체가 제일 먼저 생성되는 Young 영역부터 알아보자. Young 영역은 3개의 영역으로 나뉜다.

  • Eden 영역
  • Survivor 영역(2개)

Survivor 영역이 2개이기 때문에 총 3개의 영역으로 나뉘는 것이다. 각 영역의 처리 절차를 순서에 따라서 기술하면 다음과 같다.

  • 새로 생성한 대부분의 객체는 Eden 영역에 위치한다.
  • Eden영역이 꽉 차면 GC(Minor GC)가 발생한다.
  • Eden 영역에서 GC(Minor GC)가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.
  • 이때 Survivor영역은 둘 중 한쪽만 사용돼야 한다.
  • 그렇기에 Minor GC가 발생할때 마다 두 군데의 Survivor 영역을 이동하며 저장된다.
  • GC가 발생할때마다 살아남은 객체들은 Age가 증가한다.
  • 일정 Age에 도달한 객체들은 Old 영역으로 이동하게 된다.

이 절차를 확인해 보면 알겠지만 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 한다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 여러분의 시스템은 정상적인 상황이 아니라고 생각하면 된다.

 

 

Old Generation

Young 영역에서 오랫동안 살아남은 객체들이 넘어오는 곳이다. 이곳 역시 꽉차면 Major GC의 과정이 수행된다. 주로 5가지의 GC방식이 존재한다.

  • Serial GC
  • Parallel GC
  • Parallel Old GC(Parallel Compacting GC)
  • Concurrent Mark & Sweep GC
  • G1(Garbage First) GC

 

*stop-the-world란 GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는것

 

Serial GC

  • GC를 처리하는 쓰레드가 1개(싱글 쓰레드)
  • 다른 GC에 비해 stop-the-world 시간이 길다
  • Mark-Compact 알고리즘 사용

 

Parallel GC

  • Java8의 default GC
  • Young 영역의 GC를 멀티쓰레드로 수행
  • 그렇기에 Serial GC에 비해 stop-the-world 시간이 짧다

 

Parallel Old GC

  • Parallel GC를 개선
  • Old영역에서도 멀티쓰레드로 GC 수행
  • Mark-Summary-Compact 알고리즘 사용

 

CMS GC

  • stop-the-world 시간을 줄이기 위해 고안됨
  • compact과정이 없음

 

G1 GC

  • CMS GC를 개선
  • Java9의 default GC
  • Heap영역을 일정한 크기의 Region으로 나눔
  • 전체 Heap이 아닌 Region단위로 탐색
  • Compact 진행

 

 

 

 

참고:

더보기

'Java' 카테고리의 다른 글

[Java] 해시/해시테이블이란?  (0) 2021.07.12
[Java] 제네릭(Generic)  (0) 2021.07.11
[Java] Thread/MultiThread 4 - 동시성 문제  (0) 2021.06.29
[Java] Static 키워드  (0) 2021.06.28
[Java] JVM 구조와 동작원리  (0) 2021.06.27

스레드는 작업의 한 단위이다. 프로세스는 독자적인 메모리를 할당받아서 서로 다른 프로세스끼리는 일반적으로 서로의 메모리 영역을 침범하지 못한다. 하지만 프로세스 내부에 있는 여러 스레드들은 서로 같은 프로세스 내부에 존재하고 있기 때문에 같은 자원을 공유하여 사용할 수 있다. 같은 자원을 공유할 수 있기 때문에 동시에 여러 가지 일을 같은 자원을 두고 수행할 수 있고, 이는 곧 병렬성의 향상으로 이어진다.

 

잠깐 동시성과 병렬성을 짚고 넘어가자

 

 

동시성 VS 병렬성

동시성 병렬성
동시에 실행되는 것 같이 보이는 것 실제로 동시에 여러 작업이 처리되는 것
싱글 코어에서 멀티 쓰레드(Multi thread)를 동작 시키는 방식 멀티 코어에서 멀티 쓰레드(Multi thread)를 동작시키는 방식
한번에 많은 것을 처리 한번에 많은 일을 처리
논리적인 개념 물리적인 개념

 

첫번째 그림은 그냥 순차적으로 실행되는 모습(싱글코어)

 

두번째 그림은 동시성으로 실행되는 모습. 실제로 작업의 흐름은 한가닥이지만 여러 작업을 번갈아가며 조금씩 수행하기에 마치 동시에 진행되는 것 처럼 보인다. 작업 전환시마다 컨텍스트 스위칭이라고 비용이 발생한다.(싱글코어)

 

세번째 그림은 병렬성 작업으로 실제로 동시에 따로 작업이 진행되는 것이다.(멀티코어)

 

 

 

쓰레드 안정이 깨지는 상황

멀티 스레드 환경에서 스레드 안전(Thread-safe)한 프로그램을 제작하기 위해서는 어떤 경우에 스레드 안전하지 않은 동작이 생기는지 먼저 만들어볼 필요가 있다. 정말 간단한 예제로, 조회수 계산 로직이 있다. 특정 글을 조회하는 순산 원래 조회수에 1을 더한 값을 저장할 것이고, 여러 사용자가 동시에 접근할 것이므로 멀티 스레드 환경에서 동작한다고 가정해 보겠다.

 

public class CountingTest {
    public static void main(String[] args) {
        Count count = new Count();
        for (int i = 0; i < 100; i++) {
            new Thread(){
                public void run(){
                    for (int j = 0; j < 100; j++) {
                        System.out.println(count.view());
                    }
                }
            }.start();
        }
    }
}
class Count {
    private int count;
    public int view() {return count++;}
    public int getCount() {return count;}
}

해당 코드를 실행시켰을 때, 100명의 사용자가 100번 조회했으므로 100 * 100, 즉 10000번의 조회수가 나올것이라 예상 할 수 있다.

하지만 실제 결과값을 보았을 때는 10000번이 아닌 그보다 더 적은 조회수가 나온다. 그 이유는 조회수를 증가시키는 로직이 두 번의 동작으로 이루어지는데 동시에 여러 스레드가 접근하여 첫 번째 동작할 때의 자원과 두 번째 동작할 때의 자원 상태가 변하기 때문이다.

 

count++는

1. count변수 값을 조회한다.

2. count변수에 조회한 값에 1을 더한 값을 저장한다.

를 수행한다. 이때 발생하는 문제가 여러 쓰레드에서 count 변수를 동시에 조회하면 발생한다.

 

 

그림처럼 쓰레드1과 2에서 동시에 count변수의 값을 조회하면 둘 다 100이라는 값에 1을 더한 값을 count변수에 다시 저장하기에 102가 나와야하지만 실제론 101이 되는 것이다.

 

 

동시성을 제어하는 방법

1. 암시적 Lock

하나의 쓰레드가 접근했을때 다른 쓰레드는 접근하지 못하도록 Lock을 거는것이다. 동시성 문제를 해결할 수 있지만 한번에 하나의 쓰레드만 접근이 가능하므로 병렬성은 매우 떨어진다. 메서드에 synchronized 키워드를 붙이면 암시적 락을 적용할 수 있다.

 

메서드 Lock

class Count {
    private int count;
    public synchronized int view() {return count++;}
}

 

변수 Lock

class Count {
    private Integer count = 0;
    public int view() {
        synchronized (this.count) {
            return count++;
        }
    }
}

 

 

2. 명시적 Lock

synchronized 키워드 없이 명시적으로 ReentrantLock을 사용하는 Lock을 명시적 Lock이라고한다. 해당 Lock의 범위를 메서드 내부에서 한정하기 어렵거나, 동시에 여러 Lock을 사용하고 싶을 때 사용한다. 

 

명시적 Lock을 사용한 예제

public class CountingTest {
    public static void main(String[] args) {
        Count count = new Count();
        for (int i = 0; i < 100; i++) {
            new Thread(){
                public void run(){
                    for (int j = 0; j < 1000; j++) {
                        count.getLock().lock();
                        System.out.println(count.view());
                        count.getLock().unlock();
                    }
                }
            }.start();
        }
    }
}
class Count {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    public int view() {
            return count++;
    }
    public Lock getLock(){
        return lock;
    };
}

 

 

3. 자원의 가시성을 책임지는 volatile

 

여러 쓰레드가 하나의 자원에 동시에 읽기/쓰기를 진행할때 항상 메모리에 접근하지 않는다. 성능 향상을 위해 CPU 캐시를 참조하여 값을 조회하는데 이 값과 메인 메모리의 값이 항상 일치하는지 보장할 수 없다. 즉, 변수를 조회하여 값을 읽었는데 실제 값과 다를 수 있다는 말이다. 실제 자원의 값(메인 메모리 값)을 볼 수 있는 개념을 자원의 가시성이라고 부르는에 이 자원의 가시성을 확보하지 못한것이다.

 

 

"멀티쓰레드 환경에서 쓰레드가 변수를 읽어올 때,

CPU 캐시에 저장된 값이 다르기 때문에 변수 값 불일치 문제가 발생"

 

 

public class SharedObject {
    public int counter = 0;
}

Thread-1은 counter값을 증가시키고 있지만 CPU Cache에만 반영되어있고 실제로 Main Memory에는 반영이 되지 않는 상태. 그렇기 때문에 Thread-2는 count값을 계속 읽어오지만 0을 가져오는 문제가 발생. 

 

 

volatile은 이러한 CPU 캐시 사용을 막는다. 해당 변수에 volatile 키워드를 붙여주면 해당 변수는 캐시에 저장되는 대상에서 제외된다. 매 번 메모리에 접근해서 실제 값을 읽어오도록 설정해서 캐시 사용으로 인한 데이터 불일치를 막는다. 실제 메모리에 저장된 값을 조회하고 이를 통해 자원의 가시성을 확보할 수 있다.

 

public class SharedObject {
    public volatile int counter = 0;
}

 

volatile은 자원의 가시성을 확보해주지만 동시성 이슈를 해결하기에는 그리 충분하지 않다. 공유 자원에 read&write를 할 때는 동기화를 통해 해당 연산이 원자성을 이루도록 설정해주어야 동시성 이슈를 해결할 수 있다.

 

 

volatile이 효과적인 경우는 하나의 스레드가 wtite를 하고 다른 하나의 스레드가 read만 할 경우다. 이 경우 read만 하는 스레드는 CPU 캐시를 사용하고 다른 스레드가 write한 값을 즉각적으로 확인하지 못한다. volatile은 이런 경우 해당 자원에 가시성을 확보하게 해 줌으로써 동시성 이슈 해결에 도움을 줄 수 있다.

 

 

 

4. 쓰레드 안전한 객체 사용

Concurrunt 패키지를 통해 쓰레드 안전한 구조를 챙길 수 있다.

class Count {
    private AtomicInteger count = new AtomicInteger(0);
    public int view() {
            return count.getAndIncrement();
    }
}

 

5. 불변 객체

String 객체처럼 한번 만들면 그 상태가 변하지 않는 객체를 불변객체라고 한다. 불변 객체는 락을 걸 필요가 없다. 내부적인 상태가 변하지 않으니 여러 스레드에서 동시에 참조해도 동시성 이슈가 발생하지 않는다는 장점이 있다. 즉, 불변 객체는 언제라도 스레드 안전.

 

불변 객체는 객체의 상태를 변화시킬 수 있는 부분을 모두 제거해야한다. setter를 만들지 말고 final로 선언하면 된다.

 

 

 

참고:

'Java' 카테고리의 다른 글

[Java] 제네릭(Generic)  (0) 2021.07.11
[Java] Garbage Collection  (4) 2021.07.01
[Java] Static 키워드  (0) 2021.06.28
[Java] JVM 구조와 동작원리  (0) 2021.06.27
[Java] Thread/MultiThread 3 - 쓰레드풀  (0) 2021.06.19

지난번 JVM 포스팅에서 다음과 같은 개념을 다뤘다.

 

이때 Method Area에는 클래스, 인터페이스, 메소드, 필드, Static 변수가 보관되고

Heap Area에는 new 키워드로 생성된 객체와 배열이 보관된다고 했었다.

 

Method Area에 저장되는 Static 키워드는 지금까지 어디엔가 많이 붙혀서 써오긴 했는데 정확히 뭐하는 놈인지 모호했다. 이 기회에 정리해보자.

 

 

한 줄 요약

static 키워드를 사용한 변수는 클래스가 메모리에 올라갈 때 자동으로 생성이 된다.

즉, 인스턴스(객체) 생성 없이 바로 사용가능 하다. (그래서 편리하고 빠르다)

 

 

non-static 멤버 VS static 멤버

non-static 멤버

1. 공간적 특성: 멤버는 객체마다 별도로 존재한다.
    1.1. 인스턴스 멤버 라고 부른다.
2. 시간적 특성: 객체 생성 시에 멤버가 생성된다.
    2.1. 객체가 생길 때 멤버도 생성된다.
    2.2. 객체 생성 후 멤버 사용이 가능하다.
    2.3. 객체가 사라지면 멤버도 사라진다.
3. 공유의 특성: 공유되지 않는다.
    3.1. 멤버는 객체 내에 각각의 공간을 유지한다.

 

static 멤버

1. 공간적 특성: 멤버는 클래스당 하나가 생성된다.
    1.1. 멤버는 객체 내부가 아닌 별도의 공간에 생성된다.
    1.2. 클래스 멤버 라고 부른다.
2. 시간적 특성: 클래스 로딩 시에 멤버가 생성된다.
    2.1. 객체가 생기기 전에 이미 생성된다.
    2.2. 객체가 생기기 전에도 사용이 가능하다. (즉, 객체를 생성하지 않고도 사용할 수 있다.)
    2.3. 객체가 사라져도 멤버는 사라지지 않는다.
    2.4. 멤버는 프로그램이 종료될 때 사라진다.
3. 공유의 특성: 동일한 클래스의 모든 객체들에 의해 공유된다.

 

 

 

 

Static 키워드를 사용하는 이유

1. 자주 변하지 않는 일정한 값이나 설정 정보같은 공용자원에 대한 접근시 매번 메모리에 로딩하는 것 보다 비용을 줄일 수 있고 효율을 높일 수 있기 때문.

 

2. 인스턴스 생성 없이 바로 사용가능하기 때문에 프로그램에서 공통으로 사용되는 데이터들을 관리할 때 사용된다.

 

 

 

 

예제로 알아보자

class Foo{
	public static String s1 = "i am static";
	public String s2 = "i am instance";
}


public class static_practice {
	public static void main(String[] args) {
		System.out.println(Foo.s1);
		System.out.println(Foo.s2);	//에러
		
		Foo foo = new Foo();
		System.out.println(foo.s1);
		System.out.println(foo.s2); 
	}
}

 

Foo라는 클래스를 만들고 문자열 변수 두개를 초기화 시켰다. 한개는 static을 붙혔다.

여기서 주목할 것은 Foo.s1은 에러가 안떴고 Foo.s2는 에러가 발생했다는 것이다.

 

 

static 변수 s1은 new 키워드를 통해 객체를 생성하지 않아도 바로 사용할 수 있다. 반면 그냥 인스턴스 변수 s2는 객체를 생성한 후 접근이 가능하므로 에러가 발생한다.

 

 

 

 

class Foo{
	public static String s1 = "i am static";
	public String s2 = "i am instance";
}


public class static_practice {
	public static void main(String[] args) {
		//System.out.println(Foo.s1);
		//System.out.println(Foo.s2);
		
		Foo foo1 = new Foo();
		System.out.println("foo1.s1: "+foo1.s1);
		System.out.println("foo1.s2: "+foo1.s2);
		
		Foo foo2 = new Foo();
		System.out.println("foo2.s1: "+foo2.s1);
		System.out.println("foo2.s2: "+foo2.s2);
		
		System.out.println("====변경====");
		
		foo2.s1 = "changed s1 (foo2)";
		foo2.s2 = "changed s2 (foo2)";
		
		System.out.println("foo1.s1: "+foo1.s1);
		System.out.println("foo1.s2: "+foo1.s2);
		System.out.println("foo2.s1: "+foo2.s1);
		System.out.println("foo2.s2: "+foo2.s2);
	}
}

 

이번에는 static의 공유 속성을 알아보는 예제다.

 

결과부터 보면 이러하다.

 

====변경==== 부분에서 foo2객체의 값들을 다 바꾸었더니 건들지도 않은 foo1 객체의 static 변수 값도 바뀌었다

foo2의 값들은 당연히 바뀌는것이고.

 

Foo클래스의 static 변수는 해당 클래스의 모든 객체에 공통으로 사용되기 때문이다.

 

이처럼 static 변수, 메서드는 클래스 원형의 것을 참조하는 형태기에 한개라도 바뀌면 다 바뀐다.

 

 

 

참고:

개발을 하면서 jvm, jdk, jre와 같은 용어들을 많이 보며 지나갔는데 한번 정리가 필요할 것 같아서 글을 쓴다.

 

JVM이란

JVM은 자바 가상머신으로 자바 바이트코드를 실행 할 수 있는 주체로 JVM 덕분에 CPU나 플랫폼(OS+CPU아키텍처)과 독릭접으로 동작 가능하다. 예를들어 리눅스에서 컴파일한 C프로그램을 윈도우에서 실행했을때 환경이 달라서 작동하지 않는다는 문제가 있다고 한다. C/C++은 플랫폼 종속적이기에 크로스컴파일이 필요하다. 

 

 

자바는 JVM이 설치된 곳이라면 어디든 똑같이 작동한다. 하지만 이 JVM은 플랫폼 종속적이라는 모순이 있는데 어찌보면 당연한 것이다. 플랫폼이 다른 환경에서 일어나는 다양한 문제들을 JVM이 한번에 퉁쳐서 해결해 주기 때문이다. 또 JVM은 다른 하드웨어와 다르게 레지스터기반이 아닌 스택기반으로 동작한다. 이 부분도 해당 플랫폼이 레지스터를 사용하는지 안하는지 알 수 없기에 플랫폼 독립적으로 사용할 수 있는 스택을 사용하는 것이다.

 

자바 프로그램은 우리가 작성한 소스코드가 JAVAC compiler를 통해 바이트코드로 변환되고 이를 JVM이 읽어들이는 방식으로 진행된다.

 

 

 

 

JVM구조

JVM의 구조는 크게 보면, Garbage Collector, Execution Engine, Class Loader, Runtime Data Area로, 4가지로 나눌 수 있다. 

 

 

1. Class Loader

JVM 내로 클래스 파일을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다. 런타임 시에 동적으로 클래스를 로드한다.

 

2. Execution Engine

클래스 로더를 통해 JVM 내의 Runtime Data Area에 배치된 바이트 코드들을 명렁어 단위로 읽어서 실행한다. 최초 JVM이 나왔을 당시에는 인터프리터 방식이었기때문에 속도가 느리다는 단점이 있었지만 JIT 컴파일러 방식을 통해 이 점을 보완하였다. JIT는 바이트 코드를 어셈블러 같은 네이티브 코드로 바꿈으로써 실행이 빠르지만 역시 변환하는데 비용이 발생한다. 이 같은 이유로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정한 기준이 넘어가면 JIT 컴파일러 방식으로 실행한다.

 

 

3. Garbage Collector

Garbage Collector(GC)는 힙 메모리 영역에 생성된 객체들 중에서 참조되지 않은 객체들을 탐색 후 제거하는 역할을 한다. 이때, GC가 역할을 하는 시간은 언제인지 정확히 알 수 없다.

 

 

4. Runtime Data Area

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역. 이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack로 나눌 수 있다. 

 

Method Area, Heap Area는 모든 쓰레드에서 공유, 나머지는 쓰레드마다 각각 존재한다.

 

이 Runtime Data Area를 살펴보자

 

4.1. Method area 

모든 쓰레드가 공유하는 메모리 영역. 메소드 영역은 클래스, 인터페이스, 메소드, 필드, Static 변수 등의 바이트 코드를 보관한다.

 

 

4.2. Heap area

모든 쓰레드가 공유하며, new 키워드로 생성된 객체와 배열이 생성되는 영역. 또한, 메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 참조되지 않는 메모리를 확인하고 제거하는 영역이다.

 

 

4.3. Stack area 

 

메서드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성한다. 그리고 메서드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장한다. 마지막으로, 메서드 수행이 끝나면 프레임별로 삭제한다.

 

 

4.4. PC Register

쓰레드가 시작될 때 생성되며, 생성될 때마다 생성되는 공간으로 쓰레드마다 하나씩 존재한다. 쓰레드가 어떤 부분을 무슨 명령으로 실행해야할 지에 대한 기록을 하는 부분으로 현재 수행중인 JVM 명령의 주소를 갖는다.

 

 

4.5. Native method stack

자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역.

 

 

 

 

 

 

참고:

https://steady-coding.tistory.com/305

 

JVM 메모리 구조란? (JAVA)

안녕하세요? 코딩 중독입니다. 오늘은 JVM 메모리 구조에 대해 알아보겠습니다. JVM이란? JVM 메모리 구조를 설명하기 전에 JVM이 무엇인지 알아야 합니다. JVM은 Java Virtual Machine의 약자로, 자바 가상

steady-coding.tistory.com

https://youtu.be/UzaGOXKVhwU

 

저번 포스팅의 마지막처럼 여러개의 쓰레드를 구현하기 위해서

Thread t1 = new Thread(task);

Thread t1 = new Thread(task);

Thread t1 = new Thread(task);

Thread t1 = new Thread(task);

Thread t1 = new Thread(task);

...

 

과 같은 무지성 선언이 좋지 않은 이유가 뭘까?

 

쓰레드 풀을 사용해야하는 이유

1. 프로그램 성능저하를 방지하기 위해

 

매번 발생되는 작업을 병렬처리하기 위해 스레드를 생성/수거하는데 따른 부담은 프로그램 전체적인 퍼포먼스 저하시킨다. 따라서 스레드풀을 만들어 놓는다.

 

 

2. 다수의 사용자 요청을 처리하기 위해

 

서비스적인 측면으로 바라볼 때, 특히 대규모 프로젝트에서 중요하다. 다수의 사용자의 요청을 수용하고, 빠르게 처리하고 대응하기 위해 스레드풀을 사용한다.

 

 

 

 

쓰레드 풀의 단점

1. 한번에 너무 많은 쓰레드를 생성하면 메모리 낭비가 발생한다

 

많은 병렬처리를 예상해서 1억개의 스레드를 만들어 놓았다고 생각해보자. 실제로 100개정도의 요청과 병렬처리를 했다. 그렇다면.. 나머지 스레드들은 아무일도 하지않고 메모리만 차지하는 최악의 경우가 발생될 수 있다.

 

 

2. 노는 스레드가 발생될 수 있다.

 

1번과 비슷하지만 조금 다르다. 

예를 들어 A,B,C 스레드 3개가 있는데, 병렬적으로 일을 처리하는 과정에서 A,B,C 작업완료 소요시간이 다른 경우 스레드 유휴시간 즉, A스레드는 아직 일이 많아서 허덕이고 있는데, B,C는 일을 다하고 A가 열심히 일하는 것을 보고 놀고만 있는 유휴시간이 발생된다. 자바에서는 이를 방지하기 위해 forkJoinPool 을 지원한다. 아래 링크를 통해 알아보자

https://hamait.tistory.com/612

 

쓰레드풀 과 ForkJoinPool

쓰레드 똑똑똑! 누구니? 쓰레드 에요.. 프로그램(프로세스) 안에서 실행 되는 하나의 흐름 단위에요. 내부에서 while 을 돌면 엄청 오랬동안 일을 할 수 도 있답니다. 쓰레드 끼리는 값 (메모리)

hamait.tistory.com

 

 

쓰레드 풀을 사용한 멀티 쓰레드 구현 예제

package Thread_Practice;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPool2 {

	public static void main(String[] args) {
		BlockingQueue<Runnable> bq = new ArrayBlockingQueue<>(1);
		
		/* corePoolSize = 100	(쓰레드 풀이 기본적으로 몇개의 쓰레드를 풀에 가지고 있을지
		 * maximumPoolSize = 100(이 값을 넘어가면 RejectedExecutionException 발생)
		 * keepAliveTime = 10	(idle 쓰레드의 keep alive time)
		 * TimeUnit.SECONDS		(keepAliveTime의 시간 단위)
		 * workQueue = bq		(corePoolSize를  넘어서는 쓰레드들을 큐잉 처리하기 위한 큐 선언)
		 * */
		ThreadPoolExecutor threadPoolExecutor
        		= new ThreadPoolExecutor(100,100,10,TimeUnit.SECONDS, bq);
		
		Runnable task = new Task2();
		for(int i=0;i<100;i++) {
			threadPoolExecutor.execute(task);
		}
		System.out.println("쓰레드 콜 종료"); 
	}

}

class Task2 implements Runnable{
	
	int num = 0;
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+", num = "+num++);
		}
	}
}

 

 

ThreadPoolExecutor threadPoolExecutor

= new ThreadPoolExecutor(corePoolSize , maximumPoolSize , keepAliveTime , TimeUnit.SECONDS , workQueue );

 

각각의 인자들은 다음의 의미를 가진다.

 

 * corePoolSize = 100 (쓰레드 풀이 기본적으로 몇개의 쓰레드를 풀에 가지고 있을지
 * maximumPoolSize = 100(이 값을 넘어가면 RejectedExecutionException 발생)
 * keepAliveTime = 10 (idle 쓰레드의 keep alive time)
 * TimeUnit.SECONDS (keepAliveTime의 시간 단위)
 * workQueue = bq (corePoolSize를  넘어서는 쓰레드들을 큐잉 처리하기 위한 큐 선언)

 

즉 위 코드는

 

[기본적으로 100개의 쓰레드를 가지고있으며]

[100개의 쓰레드가 넘어가면 예외가 발생하고]

[keepAliveTime 가 10초이며]

[ArrayBlockingQueue를 사용한 쓰레드 큐잉]

 

을 하는 쓰레드 풀을 선언한 것이다

 

실행결과는 더보기를 누르면 나온다.

 

더보기

pool-1-thread-2, num = 0
pool-1-thread-3, num = 2
pool-1-thread-3, num = 4
pool-1-thread-3, num = 5
pool-1-thread-1, num = 1
pool-1-thread-4, num = 7
pool-1-thread-3, num = 6
pool-1-thread-2, num = 3
pool-1-thread-3, num = 10
pool-1-thread-5, num = 12
pool-1-thread-4, num = 9
pool-1-thread-4, num = 15
pool-1-thread-1, num = 8
pool-1-thread-1, num = 17
pool-1-thread-4, num = 16
pool-1-thread-6, num = 20
pool-1-thread-6, num = 21
pool-1-thread-6, num = 22
pool-1-thread-6, num = 23
pool-1-thread-6, num = 24
pool-1-thread-6, num = 25
pool-1-thread-6, num = 26
pool-1-thread-6, num = 27
pool-1-thread-6, num = 28
pool-1-thread-6, num = 29
pool-1-thread-1, num = 18
pool-1-thread-7, num = 30
pool-1-thread-7, num = 32
pool-1-thread-7, num = 33
pool-1-thread-7, num = 34
pool-1-thread-7, num = 35
pool-1-thread-7, num = 36
pool-1-thread-7, num = 37
pool-1-thread-7, num = 38
pool-1-thread-7, num = 39
pool-1-thread-7, num = 40
pool-1-thread-5, num = 14
pool-1-thread-5, num = 41
pool-1-thread-5, num = 42
pool-1-thread-5, num = 43
pool-1-thread-5, num = 44
pool-1-thread-5, num = 45
pool-1-thread-5, num = 46
pool-1-thread-3, num = 13
pool-1-thread-2, num = 11
pool-1-thread-3, num = 48
pool-1-thread-5, num = 47
pool-1-thread-1, num = 31
pool-1-thread-1, num = 52
pool-1-thread-1, num = 53
pool-1-thread-1, num = 54
pool-1-thread-1, num = 55
pool-1-thread-1, num = 56
pool-1-thread-4, num = 19
pool-1-thread-4, num = 57
pool-1-thread-4, num = 58
pool-1-thread-4, num = 59
pool-1-thread-4, num = 60
pool-1-thread-4, num = 61
pool-1-thread-5, num = 51
pool-1-thread-3, num = 50
pool-1-thread-3, num = 62
pool-1-thread-3, num = 63
pool-1-thread-2, num = 49
pool-1-thread-2, num = 64
pool-1-thread-2, num = 65
pool-1-thread-2, num = 66
pool-1-thread-2, num = 67
pool-1-thread-2, num = 68
pool-1-thread-2, num = 69
pool-1-thread-12, num = 70
pool-1-thread-12, num = 71
pool-1-thread-12, num = 72
pool-1-thread-12, num = 73
pool-1-thread-11, num = 74
pool-1-thread-11, num = 76
pool-1-thread-10, num = 77
pool-1-thread-10, num = 79
pool-1-thread-10, num = 80
pool-1-thread-10, num = 81
pool-1-thread-10, num = 83
pool-1-thread-10, num = 84
pool-1-thread-10, num = 85
pool-1-thread-10, num = 86
pool-1-thread-10, num = 87
pool-1-thread-10, num = 88
pool-1-thread-13, num = 82
pool-1-thread-13, num = 89
pool-1-thread-13, num = 90
pool-1-thread-13, num = 91
pool-1-thread-13, num = 92
pool-1-thread-13, num = 93
pool-1-thread-13, num = 94
pool-1-thread-13, num = 95
pool-1-thread-13, num = 96
pool-1-thread-13, num = 97
pool-1-thread-9, num = 98
pool-1-thread-9, num = 99
pool-1-thread-9, num = 100
pool-1-thread-9, num = 101
pool-1-thread-9, num = 102
pool-1-thread-9, num = 103
pool-1-thread-9, num = 104
pool-1-thread-9, num = 105
pool-1-thread-9, num = 106
pool-1-thread-9, num = 107
pool-1-thread-12, num = 75
pool-1-thread-12, num = 108
pool-1-thread-12, num = 109
pool-1-thread-12, num = 110
pool-1-thread-12, num = 111
pool-1-thread-12, num = 112
pool-1-thread-11, num = 78
pool-1-thread-11, num = 113
pool-1-thread-11, num = 114
pool-1-thread-11, num = 115
pool-1-thread-11, num = 116
pool-1-thread-11, num = 117
pool-1-thread-11, num = 118
pool-1-thread-11, num = 119
pool-1-thread-8, num = 120
pool-1-thread-8, num = 121
pool-1-thread-8, num = 122
pool-1-thread-8, num = 123
pool-1-thread-8, num = 124
pool-1-thread-8, num = 125
pool-1-thread-8, num = 126
pool-1-thread-8, num = 127
pool-1-thread-8, num = 128
pool-1-thread-8, num = 129
pool-1-thread-15, num = 131
pool-1-thread-15, num = 132
pool-1-thread-15, num = 133
pool-1-thread-15, num = 134
pool-1-thread-15, num = 135
pool-1-thread-15, num = 136
pool-1-thread-15, num = 137
pool-1-thread-15, num = 138
pool-1-thread-15, num = 139
pool-1-thread-15, num = 140
pool-1-thread-14, num = 130
pool-1-thread-14, num = 141
pool-1-thread-14, num = 142
pool-1-thread-14, num = 143
pool-1-thread-14, num = 144
pool-1-thread-14, num = 145
pool-1-thread-14, num = 146
pool-1-thread-14, num = 147
pool-1-thread-14, num = 148
pool-1-thread-14, num = 149
pool-1-thread-16, num = 150
pool-1-thread-16, num = 151
pool-1-thread-16, num = 152
pool-1-thread-16, num = 153
pool-1-thread-16, num = 154
pool-1-thread-16, num = 155
pool-1-thread-16, num = 156
pool-1-thread-17, num = 157
pool-1-thread-17, num = 159
pool-1-thread-17, num = 160
pool-1-thread-17, num = 161
pool-1-thread-17, num = 162
pool-1-thread-17, num = 163
pool-1-thread-17, num = 164
pool-1-thread-17, num = 165
pool-1-thread-17, num = 166
pool-1-thread-17, num = 167
pool-1-thread-16, num = 158
pool-1-thread-16, num = 168
pool-1-thread-16, num = 169
pool-1-thread-18, num = 170
pool-1-thread-18, num = 171
pool-1-thread-18, num = 172
pool-1-thread-18, num = 173
pool-1-thread-18, num = 174
pool-1-thread-18, num = 175
pool-1-thread-18, num = 176
pool-1-thread-18, num = 177
pool-1-thread-18, num = 178
pool-1-thread-18, num = 179
pool-1-thread-19, num = 180
pool-1-thread-19, num = 182
pool-1-thread-19, num = 183
pool-1-thread-19, num = 184
pool-1-thread-19, num = 185
pool-1-thread-19, num = 186
pool-1-thread-19, num = 187
pool-1-thread-19, num = 188
pool-1-thread-20, num = 181
pool-1-thread-20, num = 189
pool-1-thread-20, num = 190
pool-1-thread-20, num = 191
pool-1-thread-20, num = 192
pool-1-thread-20, num = 193
pool-1-thread-20, num = 194
pool-1-thread-20, num = 195
pool-1-thread-20, num = 196
pool-1-thread-20, num = 197
pool-1-thread-19, num = 198
pool-1-thread-19, num = 199
pool-1-thread-21, num = 200
pool-1-thread-21, num = 201
pool-1-thread-21, num = 202
pool-1-thread-22, num = 203
pool-1-thread-22, num = 204
pool-1-thread-22, num = 205
pool-1-thread-22, num = 206
pool-1-thread-22, num = 207
pool-1-thread-22, num = 209
pool-1-thread-22, num = 210
pool-1-thread-22, num = 211
pool-1-thread-22, num = 212
pool-1-thread-22, num = 213
pool-1-thread-23, num = 208
pool-1-thread-23, num = 215
pool-1-thread-23, num = 216
pool-1-thread-23, num = 217
pool-1-thread-23, num = 218
pool-1-thread-23, num = 219
pool-1-thread-23, num = 220
pool-1-thread-23, num = 221
pool-1-thread-23, num = 222
pool-1-thread-23, num = 223
pool-1-thread-21, num = 214
pool-1-thread-21, num = 224
pool-1-thread-21, num = 225
pool-1-thread-21, num = 226
pool-1-thread-21, num = 227
pool-1-thread-21, num = 228
pool-1-thread-21, num = 229
pool-1-thread-24, num = 230
pool-1-thread-25, num = 231
pool-1-thread-25, num = 232
pool-1-thread-25, num = 233
pool-1-thread-25, num = 234
pool-1-thread-25, num = 235
pool-1-thread-25, num = 236
pool-1-thread-25, num = 237
pool-1-thread-25, num = 238
pool-1-thread-25, num = 239
pool-1-thread-25, num = 240
pool-1-thread-24, num = 241
pool-1-thread-26, num = 242
pool-1-thread-24, num = 243
pool-1-thread-24, num = 244
pool-1-thread-24, num = 246
pool-1-thread-24, num = 247
pool-1-thread-24, num = 248
pool-1-thread-24, num = 249
pool-1-thread-24, num = 250
pool-1-thread-24, num = 251
pool-1-thread-26, num = 245
pool-1-thread-26, num = 252
pool-1-thread-26, num = 253
pool-1-thread-26, num = 254
pool-1-thread-26, num = 255
pool-1-thread-26, num = 256
pool-1-thread-26, num = 257
pool-1-thread-26, num = 258
pool-1-thread-26, num = 259
pool-1-thread-27, num = 260
pool-1-thread-27, num = 261
pool-1-thread-27, num = 262
pool-1-thread-27, num = 263
pool-1-thread-27, num = 264
pool-1-thread-28, num = 265
pool-1-thread-28, num = 267
pool-1-thread-28, num = 268
pool-1-thread-28, num = 269
pool-1-thread-28, num = 270
pool-1-thread-28, num = 271
pool-1-thread-27, num = 266
pool-1-thread-27, num = 274
pool-1-thread-27, num = 275
pool-1-thread-27, num = 276
pool-1-thread-27, num = 277
pool-1-thread-28, num = 272
pool-1-thread-28, num = 278
pool-1-thread-28, num = 280
pool-1-thread-28, num = 281
pool-1-thread-29, num = 282
pool-1-thread-29, num = 283
pool-1-thread-29, num = 284
pool-1-thread-29, num = 285
pool-1-thread-29, num = 286
pool-1-thread-29, num = 287
pool-1-thread-29, num = 288
pool-1-thread-29, num = 289
pool-1-thread-29, num = 290
pool-1-thread-29, num = 291
pool-1-thread-30, num = 273
pool-1-thread-30, num = 292
pool-1-thread-30, num = 293
pool-1-thread-30, num = 294
pool-1-thread-30, num = 295
pool-1-thread-30, num = 296
pool-1-thread-30, num = 297
pool-1-thread-30, num = 298
pool-1-thread-30, num = 299
pool-1-thread-30, num = 300
pool-1-thread-31, num = 279
pool-1-thread-31, num = 301
pool-1-thread-31, num = 302
pool-1-thread-31, num = 303
pool-1-thread-31, num = 304
pool-1-thread-31, num = 305
pool-1-thread-31, num = 306
pool-1-thread-31, num = 307
pool-1-thread-31, num = 308
pool-1-thread-31, num = 309
pool-1-thread-32, num = 310
pool-1-thread-33, num = 311
pool-1-thread-33, num = 312
pool-1-thread-34, num = 313
pool-1-thread-34, num = 314
pool-1-thread-34, num = 315
pool-1-thread-34, num = 316
pool-1-thread-34, num = 317
pool-1-thread-34, num = 318
pool-1-thread-34, num = 319
pool-1-thread-34, num = 321
pool-1-thread-34, num = 322
pool-1-thread-34, num = 323
pool-1-thread-33, num = 320
pool-1-thread-33, num = 324
pool-1-thread-33, num = 325
pool-1-thread-33, num = 326
pool-1-thread-33, num = 327
pool-1-thread-33, num = 328
pool-1-thread-33, num = 329
pool-1-thread-33, num = 330
pool-1-thread-32, num = 331
pool-1-thread-32, num = 332
pool-1-thread-32, num = 333
pool-1-thread-32, num = 334
pool-1-thread-32, num = 335
pool-1-thread-32, num = 336
pool-1-thread-32, num = 337
pool-1-thread-32, num = 338
pool-1-thread-32, num = 339
pool-1-thread-37, num = 340
pool-1-thread-37, num = 341
pool-1-thread-37, num = 342
pool-1-thread-37, num = 343
pool-1-thread-37, num = 344
pool-1-thread-37, num = 345
pool-1-thread-37, num = 346
pool-1-thread-37, num = 347
pool-1-thread-37, num = 348
pool-1-thread-37, num = 349
pool-1-thread-36, num = 340
pool-1-thread-36, num = 350
pool-1-thread-36, num = 351
pool-1-thread-36, num = 352
pool-1-thread-36, num = 353
pool-1-thread-36, num = 354
pool-1-thread-36, num = 355
pool-1-thread-36, num = 356
pool-1-thread-36, num = 357
pool-1-thread-36, num = 358
pool-1-thread-38, num = 359
pool-1-thread-38, num = 360
pool-1-thread-38, num = 361
pool-1-thread-38, num = 362
pool-1-thread-38, num = 363
pool-1-thread-38, num = 364
pool-1-thread-38, num = 365
pool-1-thread-38, num = 366
pool-1-thread-38, num = 367
pool-1-thread-38, num = 368
pool-1-thread-39, num = 369
pool-1-thread-39, num = 370
pool-1-thread-39, num = 371
pool-1-thread-39, num = 372
pool-1-thread-39, num = 374
pool-1-thread-39, num = 375
pool-1-thread-39, num = 376
pool-1-thread-39, num = 377
pool-1-thread-39, num = 379
pool-1-thread-39, num = 380
pool-1-thread-41, num = 381
pool-1-thread-41, num = 382
pool-1-thread-41, num = 383
pool-1-thread-41, num = 384
pool-1-thread-41, num = 385
pool-1-thread-41, num = 386
pool-1-thread-41, num = 387
pool-1-thread-41, num = 388
pool-1-thread-41, num = 389
pool-1-thread-41, num = 390
pool-1-thread-42, num = 391
pool-1-thread-42, num = 392
pool-1-thread-42, num = 393
pool-1-thread-42, num = 394
pool-1-thread-42, num = 395
pool-1-thread-42, num = 396
pool-1-thread-42, num = 397
pool-1-thread-42, num = 398
pool-1-thread-42, num = 399
pool-1-thread-42, num = 400
pool-1-thread-35, num = 373
pool-1-thread-35, num = 401
pool-1-thread-35, num = 402
pool-1-thread-35, num = 403
pool-1-thread-35, num = 404
pool-1-thread-35, num = 405
pool-1-thread-35, num = 406
pool-1-thread-35, num = 407
pool-1-thread-35, num = 408
pool-1-thread-35, num = 409
pool-1-thread-43, num = 410
pool-1-thread-43, num = 411
pool-1-thread-43, num = 412
pool-1-thread-43, num = 413
pool-1-thread-43, num = 414
pool-1-thread-43, num = 415
pool-1-thread-40, num = 378
pool-1-thread-40, num = 417
pool-1-thread-40, num = 418
pool-1-thread-40, num = 419
pool-1-thread-40, num = 420
pool-1-thread-40, num = 421
pool-1-thread-40, num = 422
pool-1-thread-40, num = 423
pool-1-thread-40, num = 424
pool-1-thread-40, num = 425
pool-1-thread-43, num = 416
pool-1-thread-43, num = 426
pool-1-thread-44, num = 427
pool-1-thread-44, num = 429
pool-1-thread-44, num = 430
pool-1-thread-44, num = 431
pool-1-thread-44, num = 432
pool-1-thread-44, num = 433
pool-1-thread-44, num = 434
pool-1-thread-44, num = 435
pool-1-thread-44, num = 436
pool-1-thread-44, num = 437
pool-1-thread-43, num = 428
pool-1-thread-43, num = 438
pool-1-thread-45, num = 439
pool-1-thread-45, num = 440
pool-1-thread-45, num = 441
pool-1-thread-45, num = 442
pool-1-thread-45, num = 443
pool-1-thread-45, num = 444
pool-1-thread-45, num = 445
pool-1-thread-45, num = 446
pool-1-thread-45, num = 447
pool-1-thread-45, num = 448
pool-1-thread-46, num = 442
pool-1-thread-46, num = 449
pool-1-thread-46, num = 450
pool-1-thread-46, num = 451
pool-1-thread-46, num = 452
pool-1-thread-46, num = 453
pool-1-thread-46, num = 454
pool-1-thread-46, num = 455
pool-1-thread-46, num = 456
pool-1-thread-46, num = 457
pool-1-thread-47, num = 458
pool-1-thread-47, num = 459
pool-1-thread-47, num = 460
pool-1-thread-47, num = 461
pool-1-thread-47, num = 462
pool-1-thread-47, num = 463
pool-1-thread-47, num = 464
pool-1-thread-47, num = 465
pool-1-thread-47, num = 466
pool-1-thread-47, num = 467
pool-1-thread-48, num = 468
pool-1-thread-48, num = 469
pool-1-thread-48, num = 471
pool-1-thread-48, num = 472
pool-1-thread-48, num = 473
pool-1-thread-48, num = 474
pool-1-thread-48, num = 475
pool-1-thread-48, num = 476
pool-1-thread-48, num = 477
pool-1-thread-48, num = 478
pool-1-thread-50, num = 470
pool-1-thread-50, num = 479
pool-1-thread-50, num = 480
pool-1-thread-50, num = 481
pool-1-thread-50, num = 483
pool-1-thread-50, num = 484
pool-1-thread-50, num = 485
pool-1-thread-50, num = 486
pool-1-thread-50, num = 487
pool-1-thread-50, num = 488
pool-1-thread-49, num = 482
pool-1-thread-49, num = 489
pool-1-thread-49, num = 490
pool-1-thread-49, num = 491
pool-1-thread-49, num = 492
pool-1-thread-49, num = 493
pool-1-thread-49, num = 494
pool-1-thread-49, num = 495
pool-1-thread-49, num = 496
pool-1-thread-51, num = 497
pool-1-thread-51, num = 499
pool-1-thread-51, num = 500
pool-1-thread-51, num = 501
pool-1-thread-51, num = 502
pool-1-thread-51, num = 503
pool-1-thread-51, num = 504
pool-1-thread-51, num = 505
pool-1-thread-51, num = 506
pool-1-thread-51, num = 507
pool-1-thread-49, num = 498
pool-1-thread-52, num = 508
pool-1-thread-52, num = 509
pool-1-thread-52, num = 511
pool-1-thread-53, num = 510
pool-1-thread-53, num = 513
pool-1-thread-53, num = 514
pool-1-thread-53, num = 515
pool-1-thread-53, num = 516
pool-1-thread-53, num = 517
pool-1-thread-53, num = 518
pool-1-thread-53, num = 519
pool-1-thread-53, num = 520
pool-1-thread-53, num = 521
pool-1-thread-52, num = 512
pool-1-thread-52, num = 522
pool-1-thread-52, num = 523
pool-1-thread-52, num = 524
pool-1-thread-52, num = 525
pool-1-thread-52, num = 526
pool-1-thread-52, num = 527
pool-1-thread-54, num = 528
pool-1-thread-54, num = 529
pool-1-thread-54, num = 530
pool-1-thread-54, num = 531
pool-1-thread-54, num = 532
pool-1-thread-54, num = 533
pool-1-thread-54, num = 534
pool-1-thread-54, num = 535
pool-1-thread-54, num = 536
pool-1-thread-54, num = 537
pool-1-thread-55, num = 538
pool-1-thread-55, num = 539
pool-1-thread-55, num = 540
pool-1-thread-55, num = 541
pool-1-thread-55, num = 542
pool-1-thread-55, num = 543
pool-1-thread-55, num = 544
pool-1-thread-55, num = 545
pool-1-thread-55, num = 546
pool-1-thread-55, num = 547
pool-1-thread-56, num = 548
pool-1-thread-56, num = 549
pool-1-thread-56, num = 550
pool-1-thread-56, num = 551
pool-1-thread-56, num = 552
pool-1-thread-56, num = 553
pool-1-thread-56, num = 554
pool-1-thread-56, num = 555
pool-1-thread-56, num = 556
pool-1-thread-57, num = 557
pool-1-thread-57, num = 559
pool-1-thread-57, num = 560
pool-1-thread-57, num = 561
pool-1-thread-57, num = 562
pool-1-thread-57, num = 563
pool-1-thread-57, num = 564
pool-1-thread-57, num = 565
pool-1-thread-57, num = 566
pool-1-thread-57, num = 567
pool-1-thread-56, num = 558
pool-1-thread-58, num = 568
pool-1-thread-58, num = 569
pool-1-thread-58, num = 570
pool-1-thread-59, num = 572
pool-1-thread-59, num = 573
pool-1-thread-59, num = 574
pool-1-thread-59, num = 575
pool-1-thread-59, num = 576
pool-1-thread-59, num = 577
pool-1-thread-59, num = 578
pool-1-thread-59, num = 579
pool-1-thread-59, num = 580
pool-1-thread-59, num = 581
pool-1-thread-58, num = 571
pool-1-thread-58, num = 582
pool-1-thread-58, num = 583
pool-1-thread-58, num = 584
pool-1-thread-58, num = 585
pool-1-thread-58, num = 586
pool-1-thread-58, num = 587
pool-1-thread-60, num = 588
pool-1-thread-60, num = 589
pool-1-thread-60, num = 590
pool-1-thread-60, num = 591
pool-1-thread-60, num = 592
pool-1-thread-60, num = 593
pool-1-thread-60, num = 594
pool-1-thread-60, num = 595
pool-1-thread-60, num = 596
pool-1-thread-60, num = 597
pool-1-thread-61, num = 598
pool-1-thread-61, num = 599
pool-1-thread-61, num = 600
pool-1-thread-61, num = 601
pool-1-thread-61, num = 602
pool-1-thread-61, num = 603
pool-1-thread-61, num = 604
pool-1-thread-61, num = 605
pool-1-thread-61, num = 606
pool-1-thread-61, num = 607
pool-1-thread-68, num = 608
pool-1-thread-68, num = 610
pool-1-thread-68, num = 611
pool-1-thread-68, num = 612
pool-1-thread-68, num = 613
pool-1-thread-68, num = 614
pool-1-thread-68, num = 615
pool-1-thread-68, num = 616
pool-1-thread-68, num = 617
pool-1-thread-68, num = 618
pool-1-thread-67, num = 609
pool-1-thread-67, num = 620
pool-1-thread-67, num = 621
pool-1-thread-67, num = 622
pool-1-thread-67, num = 623
pool-1-thread-67, num = 624
pool-1-thread-67, num = 625
pool-1-thread-67, num = 626
pool-1-thread-67, num = 627
pool-1-thread-67, num = 629
pool-1-thread-63, num = 619
pool-1-thread-66, num = 631
pool-1-thread-65, num = 633
pool-1-thread-65, num = 635
pool-1-thread-64, num = 630
pool-1-thread-64, num = 638
pool-1-thread-64, num = 639
pool-1-thread-64, num = 640
pool-1-thread-64, num = 641
pool-1-thread-64, num = 642
pool-1-thread-64, num = 643
pool-1-thread-64, num = 644
pool-1-thread-64, num = 645
pool-1-thread-64, num = 646
pool-1-thread-65, num = 637
pool-1-thread-65, num = 648
pool-1-thread-65, num = 649
pool-1-thread-65, num = 650
pool-1-thread-65, num = 651
pool-1-thread-65, num = 652
pool-1-thread-65, num = 653
pool-1-thread-65, num = 654
pool-1-thread-62, num = 628
pool-1-thread-62, num = 657
pool-1-thread-62, num = 658
pool-1-thread-62, num = 659
pool-1-thread-62, num = 660
pool-1-thread-62, num = 661
pool-1-thread-62, num = 662
pool-1-thread-62, num = 663
pool-1-thread-62, num = 664
pool-1-thread-62, num = 665
pool-1-thread-72, num = 666
pool-1-thread-72, num = 667
pool-1-thread-72, num = 668
pool-1-thread-72, num = 669
pool-1-thread-72, num = 670
pool-1-thread-72, num = 671
pool-1-thread-72, num = 672
pool-1-thread-72, num = 673
pool-1-thread-72, num = 674
pool-1-thread-72, num = 675
pool-1-thread-74, num = 676
pool-1-thread-74, num = 677
pool-1-thread-74, num = 678
pool-1-thread-74, num = 679
pool-1-thread-74, num = 680
pool-1-thread-74, num = 682
pool-1-thread-73, num = 656
pool-1-thread-73, num = 685
pool-1-thread-73, num = 686
pool-1-thread-73, num = 687
pool-1-thread-73, num = 688
pool-1-thread-73, num = 689
pool-1-thread-73, num = 690
pool-1-thread-73, num = 691
pool-1-thread-73, num = 692
pool-1-thread-73, num = 693
pool-1-thread-78, num = 694
pool-1-thread-78, num = 695
pool-1-thread-78, num = 696
pool-1-thread-78, num = 697
pool-1-thread-78, num = 698
pool-1-thread-78, num = 699
pool-1-thread-78, num = 700
pool-1-thread-92, num = 701
pool-1-thread-92, num = 704
pool-1-thread-71, num = 655
pool-1-thread-71, num = 706
pool-1-thread-71, num = 707
pool-1-thread-70, num = 647
pool-1-thread-70, num = 710
pool-1-thread-70, num = 712
pool-1-thread-70, num = 713
pool-1-thread-69, num = 636
pool-1-thread-69, num = 716
pool-1-thread-69, num = 718
pool-1-thread-69, num = 719
pool-1-thread-66, num = 634
쓰레드 콜 종료
pool-1-thread-89, num = 725
pool-1-thread-89, num = 726
pool-1-thread-89, num = 727
pool-1-thread-89, num = 728
pool-1-thread-89, num = 729
pool-1-thread-89, num = 730
pool-1-thread-89, num = 731
pool-1-thread-89, num = 732
pool-1-thread-89, num = 733
pool-1-thread-89, num = 734
pool-1-thread-63, num = 632
pool-1-thread-76, num = 738
pool-1-thread-76, num = 741
pool-1-thread-76, num = 742
pool-1-thread-76, num = 743
pool-1-thread-76, num = 744
pool-1-thread-76, num = 745
pool-1-thread-76, num = 746
pool-1-thread-76, num = 747
pool-1-thread-76, num = 748
pool-1-thread-90, num = 737
pool-1-thread-90, num = 750
pool-1-thread-88, num = 735
pool-1-thread-88, num = 754
pool-1-thread-88, num = 755
pool-1-thread-88, num = 756
pool-1-thread-88, num = 757
pool-1-thread-88, num = 758
pool-1-thread-88, num = 759
pool-1-thread-88, num = 760
pool-1-thread-88, num = 761
pool-1-thread-88, num = 762
pool-1-thread-93, num = 736
pool-1-thread-93, num = 763
pool-1-thread-97, num = 765
pool-1-thread-97, num = 766
pool-1-thread-87, num = 724
pool-1-thread-87, num = 769
pool-1-thread-87, num = 770
pool-1-thread-87, num = 771
pool-1-thread-87, num = 772
pool-1-thread-87, num = 774
pool-1-thread-87, num = 775
pool-1-thread-98, num = 776
pool-1-thread-98, num = 778
pool-1-thread-98, num = 779
pool-1-thread-98, num = 780
pool-1-thread-98, num = 781
pool-1-thread-98, num = 782
pool-1-thread-98, num = 783
pool-1-thread-98, num = 784
pool-1-thread-84, num = 723
pool-1-thread-84, num = 787
pool-1-thread-84, num = 788
pool-1-thread-84, num = 790
pool-1-thread-84, num = 791
pool-1-thread-66, num = 722
pool-1-thread-66, num = 793
pool-1-thread-66, num = 794
pool-1-thread-66, num = 795
pool-1-thread-66, num = 796
pool-1-thread-66, num = 797
pool-1-thread-66, num = 798
pool-1-thread-66, num = 799
pool-1-thread-69, num = 721
pool-1-thread-69, num = 800
pool-1-thread-69, num = 801
pool-1-thread-69, num = 802
pool-1-thread-69, num = 803
pool-1-thread-69, num = 804
pool-1-thread-85, num = 720
pool-1-thread-85, num = 805
pool-1-thread-85, num = 806
pool-1-thread-85, num = 807
pool-1-thread-85, num = 808
pool-1-thread-85, num = 809
pool-1-thread-85, num = 810
pool-1-thread-85, num = 811
pool-1-thread-85, num = 812
pool-1-thread-85, num = 813
pool-1-thread-83, num = 717
pool-1-thread-83, num = 814
pool-1-thread-83, num = 815
pool-1-thread-83, num = 816
pool-1-thread-70, num = 715
pool-1-thread-70, num = 818
pool-1-thread-70, num = 819
pool-1-thread-82, num = 714
pool-1-thread-82, num = 821
pool-1-thread-82, num = 822
pool-1-thread-82, num = 823
pool-1-thread-82, num = 824
pool-1-thread-82, num = 825
pool-1-thread-82, num = 826
pool-1-thread-82, num = 827
pool-1-thread-82, num = 828
pool-1-thread-81, num = 711
pool-1-thread-81, num = 830
pool-1-thread-81, num = 831
pool-1-thread-81, num = 832
pool-1-thread-71, num = 709
pool-1-thread-71, num = 834
pool-1-thread-71, num = 835
pool-1-thread-71, num = 836
pool-1-thread-71, num = 837
pool-1-thread-71, num = 838
pool-1-thread-71, num = 839
pool-1-thread-80, num = 708
pool-1-thread-80, num = 840
pool-1-thread-80, num = 841
pool-1-thread-80, num = 842
pool-1-thread-80, num = 843
pool-1-thread-80, num = 844
pool-1-thread-80, num = 845
pool-1-thread-92, num = 705
pool-1-thread-92, num = 847
pool-1-thread-92, num = 848
pool-1-thread-79, num = 703
pool-1-thread-79, num = 850
pool-1-thread-79, num = 851
pool-1-thread-79, num = 852
pool-1-thread-79, num = 853
pool-1-thread-79, num = 854
pool-1-thread-79, num = 855
pool-1-thread-78, num = 702
pool-1-thread-78, num = 857
pool-1-thread-78, num = 858
pool-1-thread-74, num = 684
pool-1-thread-74, num = 859
pool-1-thread-74, num = 860
pool-1-thread-74, num = 861
pool-1-thread-77, num = 683
pool-1-thread-77, num = 862
pool-1-thread-77, num = 863
pool-1-thread-77, num = 864
pool-1-thread-77, num = 865
pool-1-thread-77, num = 866
pool-1-thread-77, num = 867
pool-1-thread-77, num = 868
pool-1-thread-77, num = 869
pool-1-thread-77, num = 870
pool-1-thread-75, num = 681
pool-1-thread-75, num = 871
pool-1-thread-75, num = 872
pool-1-thread-75, num = 873
pool-1-thread-75, num = 874
pool-1-thread-75, num = 875
pool-1-thread-75, num = 876
pool-1-thread-79, num = 856
pool-1-thread-79, num = 878
pool-1-thread-79, num = 879
pool-1-thread-92, num = 849
pool-1-thread-92, num = 880
pool-1-thread-92, num = 881
pool-1-thread-92, num = 882
pool-1-thread-92, num = 883
pool-1-thread-80, num = 846
pool-1-thread-80, num = 884
pool-1-thread-80, num = 885
pool-1-thread-81, num = 833
pool-1-thread-81, num = 886
pool-1-thread-81, num = 887
pool-1-thread-82, num = 829
pool-1-thread-70, num = 820
pool-1-thread-70, num = 889
pool-1-thread-83, num = 817
pool-1-thread-83, num = 891
pool-1-thread-83, num = 892
pool-1-thread-84, num = 792
pool-1-thread-84, num = 894
pool-1-thread-99, num = 789
pool-1-thread-99, num = 896
pool-1-thread-99, num = 897
pool-1-thread-99, num = 898
pool-1-thread-99, num = 899
pool-1-thread-98, num = 786
pool-1-thread-98, num = 901
pool-1-thread-100, num = 785
pool-1-thread-100, num = 902
pool-1-thread-87, num = 777
pool-1-thread-87, num = 904
pool-1-thread-95, num = 773
pool-1-thread-95, num = 906
pool-1-thread-95, num = 907
pool-1-thread-95, num = 908
pool-1-thread-95, num = 909
pool-1-thread-95, num = 910
pool-1-thread-95, num = 911
pool-1-thread-95, num = 912
pool-1-thread-95, num = 913
pool-1-thread-95, num = 914
pool-1-thread-97, num = 768
pool-1-thread-97, num = 915
pool-1-thread-97, num = 916
pool-1-thread-97, num = 917
pool-1-thread-97, num = 918
pool-1-thread-97, num = 919
pool-1-thread-97, num = 920
pool-1-thread-97, num = 921
pool-1-thread-96, num = 767
pool-1-thread-96, num = 922
pool-1-thread-96, num = 923
pool-1-thread-96, num = 924
pool-1-thread-96, num = 925
pool-1-thread-96, num = 926
pool-1-thread-96, num = 927
pool-1-thread-96, num = 928
pool-1-thread-96, num = 929
pool-1-thread-96, num = 930
pool-1-thread-93, num = 764
pool-1-thread-93, num = 931
pool-1-thread-86, num = 753
pool-1-thread-86, num = 933
pool-1-thread-86, num = 934
pool-1-thread-86, num = 935
pool-1-thread-86, num = 936
pool-1-thread-86, num = 937
pool-1-thread-86, num = 938
pool-1-thread-86, num = 939
pool-1-thread-90, num = 752
pool-1-thread-90, num = 941
pool-1-thread-90, num = 942
pool-1-thread-90, num = 943
pool-1-thread-94, num = 751
pool-1-thread-94, num = 945
pool-1-thread-94, num = 946
pool-1-thread-94, num = 947
pool-1-thread-76, num = 749
pool-1-thread-91, num = 740
pool-1-thread-91, num = 949
pool-1-thread-91, num = 950
pool-1-thread-91, num = 951
pool-1-thread-91, num = 952
pool-1-thread-91, num = 953
pool-1-thread-91, num = 954
pool-1-thread-91, num = 955
pool-1-thread-91, num = 956
pool-1-thread-63, num = 739
pool-1-thread-63, num = 958
pool-1-thread-63, num = 959
pool-1-thread-63, num = 960
pool-1-thread-63, num = 961
pool-1-thread-91, num = 957
pool-1-thread-94, num = 948
pool-1-thread-94, num = 963
pool-1-thread-94, num = 964
pool-1-thread-94, num = 965
pool-1-thread-90, num = 944
pool-1-thread-90, num = 967
pool-1-thread-90, num = 968
pool-1-thread-90, num = 969
pool-1-thread-86, num = 940
pool-1-thread-86, num = 970
pool-1-thread-93, num = 932
pool-1-thread-93, num = 971
pool-1-thread-93, num = 972
pool-1-thread-93, num = 973
pool-1-thread-87, num = 905
pool-1-thread-100, num = 903
pool-1-thread-100, num = 975
pool-1-thread-100, num = 976
pool-1-thread-100, num = 977
pool-1-thread-99, num = 900
pool-1-thread-99, num = 979
pool-1-thread-99, num = 980
pool-1-thread-99, num = 981
pool-1-thread-84, num = 895
pool-1-thread-84, num = 983
pool-1-thread-84, num = 984
pool-1-thread-83, num = 893
pool-1-thread-83, num = 985
pool-1-thread-83, num = 986
pool-1-thread-70, num = 890
pool-1-thread-81, num = 888
pool-1-thread-81, num = 987
pool-1-thread-81, num = 988
pool-1-thread-75, num = 877
pool-1-thread-75, num = 989
pool-1-thread-75, num = 990
pool-1-thread-99, num = 982
pool-1-thread-100, num = 978
pool-1-thread-100, num = 991
pool-1-thread-100, num = 992
pool-1-thread-100, num = 993
pool-1-thread-93, num = 974
pool-1-thread-93, num = 994
pool-1-thread-94, num = 966
pool-1-thread-94, num = 995
pool-1-thread-63, num = 962
pool-1-thread-63, num = 996
pool-1-thread-63, num = 997

이런 결과가 나온다.

 

 

pool-1-thread-1 ~ pool-1-thread-100의 쓰레드가 동작한다.

 

 

num을 1000까지 증가시키기위해 100개의 쓰레드드리이 각각 10번의 연산을 한 모습이다.

이때 맨 마지막의 numdl 997로 끝난것을 보아 num의 값들이 순서대로 증가한것이 아니라는 것을 알 수 있는데 이는  num++ 오퍼레시연이 Thread Safe하지 않음을 의미한다. 이에대한 해결방법은 추후에 공부하도록 해보자!

 

 

다시 위의 코드에서 corePoolSize을 1로 설정하고 실행해보자, 즉 쓰레드풀에 기본적으로 1개의쓰레드를 가지고 시작한다는 의미이다.

 

 

결과는 다음과 같다

 

더보기

pool-1-thread-2, num = 0
pool-1-thread-2, num = 3
pool-1-thread-2, num = 4
pool-1-thread-2, num = 5
pool-1-thread-3, num = 2
pool-1-thread-1, num = 1
pool-1-thread-3, num = 7
pool-1-thread-2, num = 6
pool-1-thread-4, num = 10
pool-1-thread-3, num = 9
pool-1-thread-1, num = 8
pool-1-thread-5, num = 14
pool-1-thread-3, num = 13
pool-1-thread-4, num = 12
pool-1-thread-2, num = 11
pool-1-thread-4, num = 18
pool-1-thread-3, num = 17
pool-1-thread-5, num = 16
pool-1-thread-1, num = 15
pool-1-thread-5, num = 22
pool-1-thread-5, num = 24
pool-1-thread-5, num = 26
pool-1-thread-5, num = 27
pool-1-thread-3, num = 21
pool-1-thread-3, num = 29
pool-1-thread-3, num = 30
pool-1-thread-3, num = 31
pool-1-thread-4, num = 20
pool-1-thread-7, num = 33
pool-1-thread-2, num = 19
pool-1-thread-2, num = 36
pool-1-thread-7, num = 35
pool-1-thread-7, num = 38
pool-1-thread-7, num = 39
pool-1-thread-4, num = 34
pool-1-thread-3, num = 32
pool-1-thread-5, num = 28
pool-1-thread-5, num = 43
pool-1-thread-5, num = 45
pool-1-thread-6, num = 25
pool-1-thread-6, num = 47
pool-1-thread-6, num = 48
pool-1-thread-1, num = 23
pool-1-thread-1, num = 50
pool-1-thread-6, num = 49
pool-1-thread-5, num = 46
pool-1-thread-6, num = 52
pool-1-thread-5, num = 53
pool-1-thread-3, num = 44
pool-1-thread-3, num = 57
pool-1-thread-3, num = 58
pool-1-thread-3, num = 59
pool-1-thread-3, num = 60
pool-1-thread-3, num = 61
pool-1-thread-3, num = 62
pool-1-thread-3, num = 63
pool-1-thread-3, num = 64
pool-1-thread-3, num = 65
pool-1-thread-3, num = 66
pool-1-thread-3, num = 67
pool-1-thread-3, num = 68
pool-1-thread-3, num = 69
pool-1-thread-3, num = 70
pool-1-thread-3, num = 71
pool-1-thread-3, num = 72
pool-1-thread-3, num = 74
pool-1-thread-3, num = 75
pool-1-thread-3, num = 76
pool-1-thread-3, num = 77
pool-1-thread-3, num = 78
pool-1-thread-3, num = 79
pool-1-thread-3, num = 80
pool-1-thread-3, num = 81
pool-1-thread-3, num = 82
pool-1-thread-3, num = 83
pool-1-thread-3, num = 84
pool-1-thread-3, num = 85
pool-1-thread-3, num = 86
pool-1-thread-11, num = 87
pool-1-thread-4, num = 42
pool-1-thread-4, num = 90
pool-1-thread-7, num = 41
pool-1-thread-4, num = 91
pool-1-thread-8, num = 40
pool-1-thread-2, num = 37
pool-1-thread-8, num = 94
pool-1-thread-4, num = 93
pool-1-thread-7, num = 92
pool-1-thread-11, num = 89
pool-1-thread-12, num = 88
pool-1-thread-10, num = 73
pool-1-thread-10, num = 101
pool-1-thread-10, num = 102
pool-1-thread-10, num = 103
pool-1-thread-10, num = 104
pool-1-thread-10, num = 106
pool-1-thread-10, num = 107
pool-1-thread-10, num = 108
pool-1-thread-3, num = 109
pool-1-thread-3, num = 111
pool-1-thread-3, num = 112
pool-1-thread-9, num = 55
pool-1-thread-5, num = 56
pool-1-thread-6, num = 54
pool-1-thread-6, num = 117
pool-1-thread-6, num = 118
pool-1-thread-15, num = 119
pool-1-thread-15, num = 121
pool-1-thread-15, num = 122
pool-1-thread-1, num = 51
pool-1-thread-15, num = 123
pool-1-thread-6, num = 120
pool-1-thread-5, num = 116
pool-1-thread-5, num = 127
pool-1-thread-5, num = 128
pool-1-thread-5, num = 129
pool-1-thread-9, num = 115
pool-1-thread-9, num = 132
pool-1-thread-9, num = 133
pool-1-thread-9, num = 134
pool-1-thread-9, num = 135
pool-1-thread-9, num = 136
pool-1-thread-17, num = 137
pool-1-thread-17, num = 139
pool-1-thread-17, num = 140
pool-1-thread-3, num = 114
pool-1-thread-14, num = 113
pool-1-thread-14, num = 143
pool-1-thread-10, num = 110
pool-1-thread-13, num = 105
pool-1-thread-12, num = 100
pool-1-thread-11, num = 99
pool-1-thread-7, num = 98
pool-1-thread-4, num = 97
pool-1-thread-7, num = 150
pool-1-thread-4, num = 151
pool-1-thread-8, num = 96
pool-1-thread-8, num = 154
pool-1-thread-2, num = 95
pool-1-thread-8, num = 155
pool-1-thread-8, num = 158
pool-1-thread-4, num = 153
pool-1-thread-7, num = 152
pool-1-thread-11, num = 149
pool-1-thread-18, num = 147
pool-1-thread-12, num = 148
pool-1-thread-20, num = 164
pool-1-thread-13, num = 146
pool-1-thread-13, num = 167
pool-1-thread-21, num = 168
pool-1-thread-21, num = 171
pool-1-thread-10, num = 145
pool-1-thread-10, num = 172
pool-1-thread-21, num = 173
pool-1-thread-21, num = 175
pool-1-thread-21, num = 176
pool-1-thread-21, num = 177
pool-1-thread-21, num = 178
pool-1-thread-14, num = 144
pool-1-thread-3, num = 142
pool-1-thread-3, num = 181
pool-1-thread-3, num = 182
pool-1-thread-3, num = 183
pool-1-thread-17, num = 141
pool-1-thread-17, num = 185
pool-1-thread-17, num = 186
pool-1-thread-9, num = 138
pool-1-thread-9, num = 189
pool-1-thread-9, num = 190
pool-1-thread-5, num = 131
pool-1-thread-5, num = 192
pool-1-thread-5, num = 193
pool-1-thread-5, num = 194
pool-1-thread-24, num = 195
pool-1-thread-24, num = 197
pool-1-thread-24, num = 198
pool-1-thread-24, num = 199
pool-1-thread-24, num = 200
pool-1-thread-24, num = 201
pool-1-thread-16, num = 130
pool-1-thread-6, num = 126
pool-1-thread-15, num = 125
pool-1-thread-15, num = 205
pool-1-thread-15, num = 206
pool-1-thread-15, num = 207
pool-1-thread-1, num = 124
pool-1-thread-15, num = 208
pool-1-thread-15, num = 210
pool-1-thread-6, num = 204
pool-1-thread-16, num = 203
pool-1-thread-24, num = 202
pool-1-thread-24, num = 215
pool-1-thread-24, num = 216
pool-1-thread-24, num = 217
pool-1-thread-5, num = 196
pool-1-thread-5, num = 219
pool-1-thread-5, num = 220
pool-1-thread-5, num = 221
pool-1-thread-5, num = 223
pool-1-thread-5, num = 224
pool-1-thread-9, num = 191
pool-1-thread-9, num = 226
pool-1-thread-9, num = 227
pool-1-thread-9, num = 228
pool-1-thread-9, num = 229
pool-1-thread-27, num = 230
pool-1-thread-27, num = 232
pool-1-thread-17, num = 188
pool-1-thread-17, num = 234
pool-1-thread-17, num = 235
pool-1-thread-17, num = 236
pool-1-thread-28, num = 237
pool-1-thread-23, num = 187
pool-1-thread-23, num = 239
pool-1-thread-23, num = 240
pool-1-thread-23, num = 241
pool-1-thread-23, num = 242
pool-1-thread-23, num = 243
pool-1-thread-23, num = 244
pool-1-thread-23, num = 245
pool-1-thread-3, num = 184
pool-1-thread-14, num = 180
pool-1-thread-21, num = 179
pool-1-thread-10, num = 174
pool-1-thread-20, num = 166
pool-1-thread-22, num = 170
pool-1-thread-13, num = 169
pool-1-thread-12, num = 165
pool-1-thread-18, num = 163
pool-1-thread-11, num = 162
pool-1-thread-11, num = 257
pool-1-thread-7, num = 161
pool-1-thread-4, num = 160
pool-1-thread-8, num = 159
pool-1-thread-19, num = 156
pool-1-thread-2, num = 157
pool-1-thread-19, num = 262
pool-1-thread-8, num = 261
pool-1-thread-4, num = 260
pool-1-thread-7, num = 259
pool-1-thread-11, num = 258
pool-1-thread-18, num = 256
pool-1-thread-12, num = 255
pool-1-thread-13, num = 254
pool-1-thread-22, num = 253
pool-1-thread-20, num = 252
pool-1-thread-28, num = 250
pool-1-thread-10, num = 251
pool-1-thread-21, num = 249
pool-1-thread-21, num = 276
pool-1-thread-21, num = 277
pool-1-thread-21, num = 278
pool-1-thread-21, num = 279
pool-1-thread-21, num = 280
pool-1-thread-21, num = 281
pool-1-thread-21, num = 282
pool-1-thread-21, num = 283
pool-1-thread-21, num = 284
pool-1-thread-21, num = 285
pool-1-thread-21, num = 286
pool-1-thread-21, num = 287
pool-1-thread-14, num = 248
pool-1-thread-3, num = 247
pool-1-thread-23, num = 246
pool-1-thread-17, num = 238
pool-1-thread-27, num = 233
pool-1-thread-9, num = 231
pool-1-thread-5, num = 225
pool-1-thread-24, num = 222
pool-1-thread-26, num = 218
pool-1-thread-16, num = 214
pool-1-thread-29, num = 298
pool-1-thread-6, num = 213
pool-1-thread-6, num = 300
pool-1-thread-6, num = 301
pool-1-thread-6, num = 302
pool-1-thread-6, num = 303
pool-1-thread-6, num = 304
pool-1-thread-25, num = 212
pool-1-thread-15, num = 211
pool-1-thread-1, num = 209
pool-1-thread-15, num = 308
pool-1-thread-15, num = 310
pool-1-thread-15, num = 311
pool-1-thread-15, num = 312
pool-1-thread-15, num = 313
pool-1-thread-15, num = 314
pool-1-thread-15, num = 315
pool-1-thread-30, num = 316
pool-1-thread-25, num = 307
pool-1-thread-25, num = 319
pool-1-thread-25, num = 320
pool-1-thread-25, num = 321
pool-1-thread-25, num = 322
pool-1-thread-29, num = 306
pool-1-thread-6, num = 305
pool-1-thread-16, num = 299
pool-1-thread-16, num = 326
pool-1-thread-26, num = 297
pool-1-thread-26, num = 329
pool-1-thread-26, num = 330
pool-1-thread-26, num = 331
pool-1-thread-26, num = 332
pool-1-thread-26, num = 333
pool-1-thread-26, num = 334
pool-1-thread-26, num = 335
pool-1-thread-26, num = 336
pool-1-thread-26, num = 337
pool-1-thread-26, num = 338
pool-1-thread-26, num = 339
pool-1-thread-26, num = 340
pool-1-thread-26, num = 341
pool-1-thread-26, num = 342
pool-1-thread-26, num = 343
pool-1-thread-26, num = 344
pool-1-thread-26, num = 345
pool-1-thread-26, num = 346
pool-1-thread-24, num = 296
pool-1-thread-5, num = 295
pool-1-thread-5, num = 349
pool-1-thread-5, num = 350
pool-1-thread-9, num = 294
pool-1-thread-27, num = 293
pool-1-thread-17, num = 292
pool-1-thread-23, num = 291
pool-1-thread-3, num = 290
pool-1-thread-3, num = 355
pool-1-thread-14, num = 289
pool-1-thread-14, num = 357
pool-1-thread-14, num = 358
pool-1-thread-21, num = 288
pool-1-thread-21, num = 361
pool-1-thread-10, num = 275
pool-1-thread-10, num = 363
pool-1-thread-28, num = 274
pool-1-thread-20, num = 273
pool-1-thread-22, num = 272
pool-1-thread-13, num = 271
pool-1-thread-12, num = 270
pool-1-thread-18, num = 269
pool-1-thread-11, num = 268
pool-1-thread-11, num = 371
pool-1-thread-7, num = 267
pool-1-thread-4, num = 266
pool-1-thread-4, num = 374
pool-1-thread-8, num = 265
pool-1-thread-19, num = 264
pool-1-thread-2, num = 263
pool-1-thread-19, num = 377
pool-1-thread-19, num = 380
pool-1-thread-8, num = 376
pool-1-thread-4, num = 375
pool-1-thread-8, num = 382
pool-1-thread-7, num = 373
pool-1-thread-11, num = 372
pool-1-thread-18, num = 370
pool-1-thread-12, num = 369
pool-1-thread-13, num = 368
pool-1-thread-13, num = 388
pool-1-thread-13, num = 389
pool-1-thread-22, num = 367
pool-1-thread-20, num = 366
pool-1-thread-20, num = 393
pool-1-thread-28, num = 365
pool-1-thread-10, num = 364
pool-1-thread-21, num = 362
pool-1-thread-21, num = 397
pool-1-thread-21, num = 398
pool-1-thread-14, num = 360
pool-1-thread-23, num = 359
pool-1-thread-23, num = 401
pool-1-thread-23, num = 402
pool-1-thread-3, num = 356
pool-1-thread-3, num = 404
pool-1-thread-17, num = 354
pool-1-thread-27, num = 353
pool-1-thread-9, num = 352
pool-1-thread-9, num = 408
pool-1-thread-5, num = 351
pool-1-thread-5, num = 410
pool-1-thread-5, num = 411
pool-1-thread-5, num = 412
pool-1-thread-5, num = 413
pool-1-thread-5, num = 414
pool-1-thread-5, num = 417
pool-1-thread-5, num = 418
pool-1-thread-5, num = 419
pool-1-thread-5, num = 420
pool-1-thread-35, num = 421
pool-1-thread-35, num = 422
pool-1-thread-35, num = 424
pool-1-thread-35, num = 425
pool-1-thread-35, num = 426
pool-1-thread-35, num = 427
pool-1-thread-35, num = 428
pool-1-thread-35, num = 429
pool-1-thread-35, num = 431
pool-1-thread-35, num = 432
pool-1-thread-24, num = 348
pool-1-thread-24, num = 433
pool-1-thread-24, num = 434
pool-1-thread-24, num = 436
pool-1-thread-26, num = 347
pool-1-thread-31, num = 328
pool-1-thread-31, num = 439
pool-1-thread-31, num = 442
pool-1-thread-31, num = 443
pool-1-thread-16, num = 327
pool-1-thread-16, num = 446
pool-1-thread-6, num = 325
pool-1-thread-29, num = 324
pool-1-thread-25, num = 323
pool-1-thread-30, num = 318
pool-1-thread-30, num = 451
pool-1-thread-15, num = 317
pool-1-thread-15, num = 453
pool-1-thread-1, num = 309
pool-1-thread-30, num = 452
pool-1-thread-25, num = 450
pool-1-thread-29, num = 449
pool-1-thread-29, num = 457
pool-1-thread-6, num = 448
pool-1-thread-29, num = 459
pool-1-thread-16, num = 447
pool-1-thread-31, num = 445
pool-1-thread-35, num = 444
pool-1-thread-35, num = 463
pool-1-thread-38, num = 440
pool-1-thread-38, num = 465
pool-1-thread-38, num = 466
pool-1-thread-5, num = 441
pool-1-thread-26, num = 438
pool-1-thread-24, num = 437
pool-1-thread-37, num = 435
pool-1-thread-36, num = 430
pool-1-thread-39, num = 423
pool-1-thread-39, num = 473
pool-1-thread-33, num = 415
pool-1-thread-34, num = 416
pool-1-thread-34, num = 476
pool-1-thread-34, num = 477
pool-1-thread-9, num = 409
pool-1-thread-27, num = 407
pool-1-thread-27, num = 480
pool-1-thread-27, num = 481
pool-1-thread-27, num = 482
pool-1-thread-17, num = 406
pool-1-thread-3, num = 405
pool-1-thread-23, num = 403
pool-1-thread-14, num = 400
pool-1-thread-21, num = 399
pool-1-thread-21, num = 488
pool-1-thread-10, num = 396
pool-1-thread-10, num = 491
pool-1-thread-10, num = 493
pool-1-thread-10, num = 494
pool-1-thread-28, num = 395
pool-1-thread-20, num = 394
pool-1-thread-20, num = 496
pool-1-thread-22, num = 392
pool-1-thread-22, num = 498
pool-1-thread-13, num = 391
pool-1-thread-11, num = 390
pool-1-thread-11, num = 500
pool-1-thread-11, num = 501
pool-1-thread-11, num = 502
pool-1-thread-11, num = 503
pool-1-thread-11, num = 504
pool-1-thread-11, num = 505
pool-1-thread-12, num = 387
pool-1-thread-18, num = 386
pool-1-thread-18, num = 509
pool-1-thread-7, num = 385
pool-1-thread-8, num = 384
pool-1-thread-8, num = 511
pool-1-thread-8, num = 513
pool-1-thread-8, num = 514
pool-1-thread-8, num = 515
pool-1-thread-8, num = 516
pool-1-thread-8, num = 517
pool-1-thread-8, num = 518
pool-1-thread-8, num = 519
pool-1-thread-18, num = 520
pool-1-thread-4, num = 383
pool-1-thread-19, num = 381
pool-1-thread-19, num = 524
pool-1-thread-19, num = 526
pool-1-thread-32, num = 379
pool-1-thread-32, num = 528
pool-1-thread-2, num = 378
pool-1-thread-32, num = 529
pool-1-thread-32, num = 531
pool-1-thread-19, num = 527
pool-1-thread-19, num = 533
pool-1-thread-13, num = 534
pool-1-thread-13, num = 536
pool-1-thread-13, num = 537
pool-1-thread-13, num = 538
pool-1-thread-13, num = 539
pool-1-thread-40, num = 525
pool-1-thread-40, num = 542
pool-1-thread-40, num = 544
pool-1-thread-40, num = 545
pool-1-thread-40, num = 546
pool-1-thread-40, num = 547
pool-1-thread-40, num = 548
pool-1-thread-40, num = 549
pool-1-thread-40, num = 550
pool-1-thread-40, num = 551
pool-1-thread-4, num = 523
pool-1-thread-18, num = 522
pool-1-thread-8, num = 521
pool-1-thread-49, num = 557
pool-1-thread-7, num = 512
pool-1-thread-46, num = 510
pool-1-thread-46, num = 560
pool-1-thread-46, num = 561
pool-1-thread-46, num = 562
pool-1-thread-46, num = 563
pool-1-thread-46, num = 564
pool-1-thread-46, num = 565
pool-1-thread-19, num = 566
pool-1-thread-12, num = 508
pool-1-thread-19, num = 568
pool-1-thread-19, num = 570
pool-1-thread-19, num = 571
pool-1-thread-19, num = 572
pool-1-thread-19, num = 573
pool-1-thread-19, num = 574
pool-1-thread-19, num = 575
pool-1-thread-19, num = 577
pool-1-thread-19, num = 578
pool-1-thread-11, num = 507
pool-1-thread-51, num = 579
pool-1-thread-51, num = 581
pool-1-thread-51, num = 582
pool-1-thread-51, num = 584
pool-1-thread-51, num = 585
pool-1-thread-51, num = 586
pool-1-thread-51, num = 587
pool-1-thread-51, num = 588
pool-1-thread-51, num = 589
pool-1-thread-51, num = 590
pool-1-thread-14, num = 506
pool-1-thread-14, num = 592
pool-1-thread-14, num = 594
pool-1-thread-14, num = 595
pool-1-thread-14, num = 596
pool-1-thread-14, num = 597
pool-1-thread-14, num = 598
pool-1-thread-14, num = 599
pool-1-thread-14, num = 600
pool-1-thread-14, num = 601
pool-1-thread-22, num = 499
pool-1-thread-22, num = 602
pool-1-thread-22, num = 603
pool-1-thread-22, num = 604
pool-1-thread-53, num = 605
pool-1-thread-53, num = 606
pool-1-thread-53, num = 607
pool-1-thread-53, num = 609
pool-1-thread-53, num = 610
pool-1-thread-53, num = 611
pool-1-thread-53, num = 612
pool-1-thread-53, num = 613
pool-1-thread-53, num = 614
pool-1-thread-53, num = 615
pool-1-thread-20, num = 497
pool-1-thread-20, num = 616
pool-1-thread-28, num = 495
pool-1-thread-28, num = 617
pool-1-thread-28, num = 618
pool-1-thread-28, num = 619
pool-1-thread-9, num = 492
pool-1-thread-51, num = 622
pool-1-thread-51, num = 624
pool-1-thread-51, num = 625
pool-1-thread-51, num = 626
pool-1-thread-51, num = 627
pool-1-thread-51, num = 628
pool-1-thread-51, num = 629
pool-1-thread-51, num = 630
pool-1-thread-51, num = 631
pool-1-thread-51, num = 632
pool-1-thread-42, num = 490
pool-1-thread-42, num = 634
pool-1-thread-42, num = 635
pool-1-thread-21, num = 489
pool-1-thread-21, num = 637
pool-1-thread-21, num = 638
pool-1-thread-21, num = 639
pool-1-thread-21, num = 640
pool-1-thread-23, num = 487
pool-1-thread-23, num = 642
pool-1-thread-23, num = 643
pool-1-thread-23, num = 645
pool-1-thread-23, num = 646
pool-1-thread-23, num = 647
pool-1-thread-3, num = 486
pool-1-thread-41, num = 485
pool-1-thread-41, num = 649
pool-1-thread-41, num = 650
pool-1-thread-17, num = 484
pool-1-thread-17, num = 653
pool-1-thread-17, num = 654
pool-1-thread-17, num = 655
pool-1-thread-17, num = 656
pool-1-thread-17, num = 657
pool-1-thread-27, num = 483
pool-1-thread-34, num = 479
pool-1-thread-34, num = 658
pool-1-thread-34, num = 659
pool-1-thread-34, num = 660
pool-1-thread-34, num = 661
pool-1-thread-34, num = 662
pool-1-thread-34, num = 663
pool-1-thread-57, num = 664
pool-1-thread-57, num = 666
pool-1-thread-57, num = 667
pool-1-thread-57, num = 668
pool-1-thread-57, num = 669
pool-1-thread-57, num = 670
pool-1-thread-57, num = 672
pool-1-thread-20, num = 673
쓰레드 콜 종료
pool-1-thread-6, num = 478
pool-1-thread-6, num = 676
pool-1-thread-6, num = 677
pool-1-thread-6, num = 678
pool-1-thread-6, num = 679
pool-1-thread-6, num = 680
pool-1-thread-6, num = 681
pool-1-thread-6, num = 682
pool-1-thread-6, num = 683
pool-1-thread-6, num = 684
pool-1-thread-33, num = 475
pool-1-thread-33, num = 685
pool-1-thread-33, num = 686
pool-1-thread-33, num = 687
pool-1-thread-33, num = 688
pool-1-thread-33, num = 689
pool-1-thread-33, num = 690
pool-1-thread-33, num = 691
pool-1-thread-33, num = 692
pool-1-thread-39, num = 474
pool-1-thread-39, num = 693
pool-1-thread-39, num = 694
pool-1-thread-39, num = 695
pool-1-thread-39, num = 696
pool-1-thread-36, num = 472
pool-1-thread-36, num = 699
pool-1-thread-36, num = 700
pool-1-thread-36, num = 701
pool-1-thread-36, num = 702
pool-1-thread-36, num = 703
pool-1-thread-36, num = 704
pool-1-thread-36, num = 705
pool-1-thread-36, num = 706
pool-1-thread-37, num = 471
pool-1-thread-37, num = 707
pool-1-thread-37, num = 708
pool-1-thread-37, num = 709
pool-1-thread-24, num = 470
pool-1-thread-24, num = 711
pool-1-thread-24, num = 712
pool-1-thread-26, num = 469
pool-1-thread-26, num = 713
pool-1-thread-26, num = 714
pool-1-thread-5, num = 468
pool-1-thread-38, num = 467
pool-1-thread-38, num = 717
pool-1-thread-38, num = 718
pool-1-thread-38, num = 719
pool-1-thread-38, num = 720
pool-1-thread-38, num = 721
pool-1-thread-35, num = 464
pool-1-thread-35, num = 723
pool-1-thread-35, num = 724
pool-1-thread-35, num = 725
pool-1-thread-31, num = 462
pool-1-thread-31, num = 727
pool-1-thread-31, num = 728
pool-1-thread-31, num = 729
pool-1-thread-31, num = 730
pool-1-thread-16, num = 461
pool-1-thread-16, num = 731
pool-1-thread-29, num = 460
pool-1-thread-29, num = 732
pool-1-thread-29, num = 733
pool-1-thread-29, num = 734
pool-1-thread-15, num = 458
pool-1-thread-15, num = 735
pool-1-thread-15, num = 736
pool-1-thread-15, num = 737
pool-1-thread-15, num = 738
pool-1-thread-15, num = 739
pool-1-thread-15, num = 740
pool-1-thread-15, num = 741
pool-1-thread-15, num = 742
pool-1-thread-15, num = 743
pool-1-thread-25, num = 456
pool-1-thread-25, num = 744
pool-1-thread-30, num = 455
pool-1-thread-30, num = 745
pool-1-thread-30, num = 746
pool-1-thread-30, num = 747
pool-1-thread-30, num = 748
pool-1-thread-30, num = 749
pool-1-thread-1, num = 454
pool-1-thread-35, num = 726
pool-1-thread-35, num = 750
pool-1-thread-35, num = 751
pool-1-thread-35, num = 752
pool-1-thread-38, num = 722
pool-1-thread-5, num = 716
pool-1-thread-5, num = 753
pool-1-thread-5, num = 754
pool-1-thread-5, num = 755
pool-1-thread-5, num = 756
pool-1-thread-5, num = 757
pool-1-thread-5, num = 758
pool-1-thread-5, num = 759
pool-1-thread-26, num = 715
pool-1-thread-26, num = 760
pool-1-thread-26, num = 761
pool-1-thread-37, num = 710
pool-1-thread-37, num = 763
pool-1-thread-37, num = 764
pool-1-thread-59, num = 698
pool-1-thread-59, num = 766
pool-1-thread-59, num = 767
pool-1-thread-59, num = 768
pool-1-thread-59, num = 769
pool-1-thread-59, num = 770
pool-1-thread-59, num = 771
pool-1-thread-59, num = 772
pool-1-thread-59, num = 773
pool-1-thread-59, num = 774
pool-1-thread-39, num = 697
pool-1-thread-57, num = 675
pool-1-thread-57, num = 776
pool-1-thread-20, num = 674
pool-1-thread-20, num = 778
pool-1-thread-20, num = 779
pool-1-thread-20, num = 780
pool-1-thread-20, num = 781
pool-1-thread-20, num = 782
pool-1-thread-20, num = 783
pool-1-thread-20, num = 784
pool-1-thread-20, num = 785
pool-1-thread-58, num = 671
pool-1-thread-58, num = 786
pool-1-thread-58, num = 787
pool-1-thread-34, num = 665
pool-1-thread-34, num = 789
pool-1-thread-34, num = 790
pool-1-thread-34, num = 791
pool-1-thread-34, num = 792
pool-1-thread-34, num = 793
pool-1-thread-34, num = 794
pool-1-thread-34, num = 795
pool-1-thread-34, num = 796
pool-1-thread-34, num = 797
pool-1-thread-41, num = 652
pool-1-thread-41, num = 798
pool-1-thread-41, num = 799
pool-1-thread-41, num = 800
pool-1-thread-41, num = 801
pool-1-thread-41, num = 802
pool-1-thread-41, num = 803
pool-1-thread-22, num = 651
pool-1-thread-22, num = 804
pool-1-thread-22, num = 805
pool-1-thread-3, num = 648
pool-1-thread-3, num = 807
pool-1-thread-3, num = 808
pool-1-thread-3, num = 809
pool-1-thread-56, num = 644
pool-1-thread-56, num = 810
pool-1-thread-56, num = 811
pool-1-thread-21, num = 641
pool-1-thread-21, num = 813
pool-1-thread-21, num = 814
pool-1-thread-42, num = 636
pool-1-thread-42, num = 816
pool-1-thread-42, num = 817
pool-1-thread-55, num = 633
pool-1-thread-55, num = 819
pool-1-thread-55, num = 820
pool-1-thread-9, num = 623
pool-1-thread-9, num = 822
pool-1-thread-9, num = 823
pool-1-thread-28, num = 621
pool-1-thread-54, num = 620
pool-1-thread-54, num = 825
pool-1-thread-54, num = 826
pool-1-thread-54, num = 827
pool-1-thread-54, num = 828
pool-1-thread-54, num = 829
pool-1-thread-54, num = 830
pool-1-thread-54, num = 831
pool-1-thread-54, num = 832
pool-1-thread-19, num = 608
pool-1-thread-19, num = 834
pool-1-thread-19, num = 835
pool-1-thread-19, num = 836
pool-1-thread-19, num = 837
pool-1-thread-19, num = 838
pool-1-thread-19, num = 839
pool-1-thread-19, num = 840
pool-1-thread-19, num = 841
pool-1-thread-19, num = 842
pool-1-thread-52, num = 593
pool-1-thread-52, num = 843
pool-1-thread-52, num = 844
pool-1-thread-52, num = 845
pool-1-thread-52, num = 846
pool-1-thread-52, num = 847
pool-1-thread-52, num = 848
pool-1-thread-52, num = 849
pool-1-thread-52, num = 850
pool-1-thread-52, num = 851
pool-1-thread-40, num = 591
pool-1-thread-40, num = 852
pool-1-thread-40, num = 853
pool-1-thread-40, num = 854
pool-1-thread-40, num = 855
pool-1-thread-40, num = 856
pool-1-thread-40, num = 857
pool-1-thread-40, num = 858
pool-1-thread-40, num = 859
pool-1-thread-40, num = 860
pool-1-thread-50, num = 583
pool-1-thread-50, num = 861
pool-1-thread-50, num = 862
pool-1-thread-50, num = 863
pool-1-thread-50, num = 864
pool-1-thread-50, num = 865
pool-1-thread-50, num = 866
pool-1-thread-50, num = 867
pool-1-thread-50, num = 868
pool-1-thread-50, num = 869
pool-1-thread-11, num = 580
pool-1-thread-11, num = 870
pool-1-thread-49, num = 576
pool-1-thread-49, num = 871
pool-1-thread-49, num = 872
pool-1-thread-49, num = 873
pool-1-thread-49, num = 874
pool-1-thread-49, num = 875
pool-1-thread-49, num = 876
pool-1-thread-49, num = 877
pool-1-thread-49, num = 878
pool-1-thread-12, num = 569
pool-1-thread-46, num = 567
pool-1-thread-46, num = 879
pool-1-thread-46, num = 880
pool-1-thread-7, num = 559
pool-1-thread-7, num = 881
pool-1-thread-7, num = 882
pool-1-thread-7, num = 883
pool-1-thread-7, num = 884
pool-1-thread-8, num = 558
pool-1-thread-8, num = 885
pool-1-thread-8, num = 886
pool-1-thread-8, num = 887
pool-1-thread-48, num = 556
pool-1-thread-48, num = 889
pool-1-thread-48, num = 890
pool-1-thread-48, num = 891
pool-1-thread-48, num = 892
pool-1-thread-48, num = 893
pool-1-thread-10, num = 555
pool-1-thread-10, num = 895
pool-1-thread-10, num = 896
pool-1-thread-10, num = 897
pool-1-thread-10, num = 898
pool-1-thread-18, num = 554
pool-1-thread-4, num = 553
pool-1-thread-44, num = 552
pool-1-thread-44, num = 900
pool-1-thread-44, num = 901
pool-1-thread-44, num = 902
pool-1-thread-44, num = 903
pool-1-thread-44, num = 904
pool-1-thread-44, num = 905
pool-1-thread-44, num = 906
pool-1-thread-44, num = 907
pool-1-thread-44, num = 908
pool-1-thread-43, num = 543
pool-1-thread-43, num = 909
pool-1-thread-43, num = 910
pool-1-thread-43, num = 911
pool-1-thread-43, num = 912
pool-1-thread-43, num = 913
pool-1-thread-43, num = 914
pool-1-thread-43, num = 915
pool-1-thread-13, num = 541
pool-1-thread-13, num = 917
pool-1-thread-13, num = 918
pool-1-thread-13, num = 919
pool-1-thread-13, num = 920
pool-1-thread-47, num = 540
pool-1-thread-47, num = 921
pool-1-thread-47, num = 922
pool-1-thread-47, num = 923
pool-1-thread-45, num = 535
pool-1-thread-45, num = 925
pool-1-thread-45, num = 926
pool-1-thread-45, num = 927
pool-1-thread-45, num = 928
pool-1-thread-45, num = 929
pool-1-thread-45, num = 930
pool-1-thread-45, num = 931
pool-1-thread-45, num = 932
pool-1-thread-45, num = 933
pool-1-thread-32, num = 532
pool-1-thread-32, num = 934
pool-1-thread-32, num = 935
pool-1-thread-2, num = 530
pool-1-thread-2, num = 937
pool-1-thread-2, num = 938
pool-1-thread-2, num = 939
pool-1-thread-2, num = 940
pool-1-thread-2, num = 941
pool-1-thread-2, num = 942
pool-1-thread-32, num = 936
pool-1-thread-32, num = 943
pool-1-thread-32, num = 944
pool-1-thread-47, num = 924
pool-1-thread-47, num = 945
pool-1-thread-47, num = 946
pool-1-thread-43, num = 916
pool-1-thread-43, num = 948
pool-1-thread-10, num = 899
pool-1-thread-10, num = 949
pool-1-thread-10, num = 950
pool-1-thread-48, num = 894
pool-1-thread-48, num = 952
pool-1-thread-48, num = 953
pool-1-thread-48, num = 954
pool-1-thread-8, num = 888
pool-1-thread-8, num = 955
pool-1-thread-8, num = 956
pool-1-thread-8, num = 957
pool-1-thread-8, num = 958
pool-1-thread-54, num = 833
pool-1-thread-9, num = 824
pool-1-thread-9, num = 959
pool-1-thread-9, num = 960
pool-1-thread-9, num = 961
pool-1-thread-9, num = 962
pool-1-thread-9, num = 963
pool-1-thread-55, num = 821
pool-1-thread-55, num = 964
pool-1-thread-55, num = 965
pool-1-thread-55, num = 966
pool-1-thread-42, num = 818
pool-1-thread-42, num = 968
pool-1-thread-42, num = 969
pool-1-thread-21, num = 815
pool-1-thread-21, num = 971
pool-1-thread-56, num = 812
pool-1-thread-56, num = 973
pool-1-thread-22, num = 806
pool-1-thread-22, num = 975
pool-1-thread-22, num = 976
pool-1-thread-22, num = 977
pool-1-thread-22, num = 978
pool-1-thread-22, num = 979
pool-1-thread-22, num = 980
pool-1-thread-58, num = 788
pool-1-thread-58, num = 981
pool-1-thread-57, num = 777
pool-1-thread-39, num = 775
pool-1-thread-39, num = 983
pool-1-thread-37, num = 765
pool-1-thread-37, num = 984
pool-1-thread-26, num = 762
pool-1-thread-26, num = 985
pool-1-thread-58, num = 982
pool-1-thread-58, num = 986
pool-1-thread-58, num = 987
pool-1-thread-58, num = 988
pool-1-thread-56, num = 974
pool-1-thread-56, num = 990
pool-1-thread-56, num = 991
pool-1-thread-56, num = 992
pool-1-thread-56, num = 993
pool-1-thread-21, num = 972
pool-1-thread-21, num = 994
pool-1-thread-42, num = 970
pool-1-thread-55, num = 967
pool-1-thread-55, num = 995
pool-1-thread-55, num = 996
pool-1-thread-10, num = 951
pool-1-thread-10, num = 997
pool-1-thread-47, num = 947
pool-1-thread-47, num = 998
pool-1-thread-58, num = 989
pool-1-thread-47, num = 999

 

 

이번 실행에서는 60개의쓰레드가 동작한 모습이다.

 

 

corePoolSize가 100일때는 100개의 쓰레드가 10번식 연산을 하였지만 이번에는 60개의 쓰레드가 N번 실행됐다. N은 10의 배수이다. run()의 포문이 10번만큼 돌기 때문에 10의 배수만큼 동작하는 것 같다.

 

 

각 쓰레드들의 동작 횟수를 세어보면 어떤 쓰레드는 10번, 어떤 쓰레드는 30번 이렇게 다 다르다. 이유는 무엇일까?

 

 

이 경우에서 corePoolSize가 1이므로 1개의 쓰레드로 시작하였다. 이 쓰레드의 연산이 끝나기 전에 새로운 task의 요청이 들어오면 쓰레드풀에선 새로운 쓰레드를 생성한다. 하지만 기존 쓰레드의 연산이 끝난 후에 새 task 요청이 들어오면 기존 쓰레드를 재사용하여 task를 수행하기에 몇번 재사용 됐느냐에 따라 각 쓰레드들의 연산 횟수가 결정되는 것이다.


이렇게 초기 corePoolSize를 1로하면 존재하는 쓰레드를 재사용하는 방식으로 최대한 효율적으로 동작하기에 불필요한 쓰레드가 줄어듬으로써 소모되는 메모리를 줄일 수 있다. 하지만 그렇다고 무조건 1로 하면 새로운 쓰레드의 생성에 드는 비용이 늘어날 것이므로 적절한 값을 찾아야 할 것 같다.

+ Recent posts