728x90

오늘은 JPA N+1의 문제 해결에 대해서 글을 공유해드리려고 합니다. 

* Java 백엔드 개발자를 위한 데이터베이스 쿼리 최적화에 적합한 내용입니다.

개발자가 직면하는 가장 일반적인 성능 병목 현상 중 하나가 N+1입니다.
애플리케이션이 단 한 번의 쿼리로 동일한 결과를 얻을 수 있는데도 N+1번의 데이터베이스 쿼리를 수행할 때 발생합니다.
과도한 데이터베이스 Hit는 느린 응답 시간, 높은 서버 부하, 열약한 사용자 경험으로 이어질 수 있습니다. 
 
원인을 함께 파악해 보고 개발자가 이러한 문제를 어떻게 완화할지에 대해서 다양한 전략과 기법에 대해서 적어보겠습니다.

앞서, N+1 문제가 무엇인지 알아보도록 하겠습니다.

N+1 문제란 무엇인가?

애플리케이션이 개체목록(예시: 제품, 사용자 또는 게시물 목록)을 가져온 다음 목록의 각 객체애 대해 추가 데이터베이스 쿼리를 수행하여 관련 데이터를 검색할 때 발생을 하게 됩니다.
예를 들어 작성자 정보와 함께 블로그 게시물 목록을 표시하는 Java 애플리케이션을 생각해 보자.
애플리케이션이 글 목록을 가져온 다음 각 글의 작성자 정보를 검색하기 위해 별도의 쿼리를 수행하면 N+1 쿼리가 발생하며, 여기서 N은 글의 수입니다. 이러한 비효율적인 쿼리 패턴은 많은 수의 데이터베이스 HIT로 빠르게 이어질 수 있습니다.
 

N+1 문제 원인

1. 지연 로딩(Lazy Loading) : 
수많은 Java ORM 프레임워크들, 가령 Hibernate에서 기본적으로 지연 로딩을 사용합니다.
지연 로딩이란 관련된 데이터를 가져올때만  데이터베이스에 가져오는 것을 의미합니다. 개발자가  컬렉션의 각 항목에 대한 관련 데이터에 접근할 때 N+1 쿼리를 발생할 수 있습니다.  
 
2.비효율적인 쿼리(Inefficient Queries)
개발자는 관련 데이터를 반복해서 가져오는 코드를 작성하여 최적화된 단일 쿼리로 충분할 수 있는 데이터베이스 쿼리를 여러 번 수행하게 될 수 있습니다.
 
3. 일괄 가져오기 부족 (Lack of Batch Fetching)
일부 ORM 프레임워크에서 제공하는 기술인 일괄 가져오기를 사용하면 단일 쿼리에서 여러 개체에 대한 관련 데이터를 검색할 수 있습니다.
개발자들은 이 기능을 간과하거나 오용하는 경우가 많습니다.
 

N+1 문제를 완화하기 위한 전략들

N+1 문제를 해결하고 과도한 데이터베이스 히트를 최소화하기 위해 Java 백엔드 엔지니어는 다양한 전략과 모범 사례를 활용할 수 있습니다

 

1. 에저 로딩 

에지 로딩을 사용하면 관련 데이터를 미리 불러와 추가 쿼리의 필요성을 줄일 수 있습니다. 대부분의 ORM 프레임워크는 관련 데이터를 로드할 시기와 방법을 지정하는 메커니즘을 제공하므로 데이터베이스 쿼리를 최적화할 수 있습니다.

2. 일괄 가져오기

ORM 프레임워크에서 제공하는 일괄 가져오기 기능을 사용하여 관련 데이터를 하나씩 가져오지 않고 일괄적으로 검색하세요. 이렇게 하면 데이터베이스 쿼리 횟수를 크게 줄일 수 있습니다. 

3. DTO 투영

데이터베이스에서 필요한 데이터만 가져오려면 DTO(데이터 전송 객체) 투영을 사용하는 것이 좋습니다. 이 접근 방식을 사용하면 검색되는 데이터의 양을 최소화하여 쿼리 속도를 높일 수 있습니다.

4. 캐싱

캐싱 메커니즘을 구현하여 자주 액세스하는 데이터를 메모리에 저장하세요. 캐싱은 반복적인 데이터베이스 쿼리의 필요성을 줄여 응답 시간을 개선하고 데이터베이스 부하를 줄이는 데 도움이 될 수 있습니다.

5. 페이지 매김 및 필터링

페이지 매김 및 필터링을 구현하여 단일 쿼리에서 검색되는 레코드 수를 제한하세요. 이는 대규모 데이터 세트를 다룰 때 특히 유용할 수 있습니다.

6. 쿼리 최적화

데이터베이스 쿼리를 정기적으로 검토하고 최적화하세요. 쿼리 실행 계획을 분석하고 데이터베이스 프로파일링 도구를 사용해 성능 병목 현상을 파악하고 해결하세요.
 

마치며

N+1 문제와 과도한 데이터베이스 히트는 Java 백엔드 엔지니어가 직면하는 일반적인 성능 문제입니다. 개발자는 N+1 문제의 원인을 이해하고 일괄 로딩, 배치 가져오기, DTO 예측, 캐싱, 페이지 매김 및 쿼리 최적화와 같은 효과적인 전략을 채택함으로써 애플리케이션의 성능을 크게 향상해 원활한 사용자 경험을 보장하고 서버 부하를 줄일 수 있습니다. N+1 문제를 해결한다는 것은 단순히 데이터베이스 쿼리를 최적화하는 것만이 아니라 사용자에게 효율적이고 확장 가능한 백엔드 솔루션을 제공하는 것입니다.
 

728x90

'DB' 카테고리의 다른 글

Database Lock 이란?  (1) 2024.06.18
PL/SQL 이란  (0) 2022.01.10
데이터베이스 모델링 -1  (0) 2022.01.07
SQL 사용자 권한  (0) 2022.01.05
SQUENCE INDEX(순차 적으로 증가하는 값)  (0) 2022.01.05
728x90

자바 8은 데이터베이스 질의 언어에서 표현식을 처리하는 것처럼 병렬 연산을 지원하는 스트림이라는 새로운 API 를 제공한다. 데이터베이스 질의 언어에서 고수준 언어로 원하는 동작을 표현하면, 구현(자바에서는 스트림 라이브러리가 이 역할을 수행) 에서 최적의 저수준 실행 방법을 선택하는 방식으로 동작한다. 즉, 스트림을 이용하면 에러를 자주 일이키며 멀티코어 CPU 를 이용하는 것보다 비용이 훨씬 비싼 키워드 synchronized를 사용하지 않아도 된다. 

더보기

멀티코어 CPU의 각 코어는 별도의 캐시(빠른 메모리) 를 포함하고 있다. 락을 사용하면 이러한 캐시가 동기화되어야 하므로 속도가 느린 캐시 일관성 프로토콜 인터코어 통신이 이루어진다.

 

조금 다른 관점에서 보면 결국 자바8에 추가된 스트림 API 덕분에 다른 두 가지 기능, 즉 메서드에 코드를 전달하는 간결 기법(메서드 참조와 람다) 과 인터페이스의 디폴트 메서드가 존재 할 수 있음을 알 수 있다. 

 

하지만 스트림 API 때문에 메서드에 코드를 전달하는 기법이 생겼다고 추리하는 것은 메서드에 코드를 전달하는 기법의 활용성을 제한할 수 있는 위험한 생각이다. 

메서드에 코드를 전달하는 기법을 이용하면 새롭고 간결한 방식으로 동작 파라미터화를 구현할 수 있다. 

 

예시 ) 약간만 다른 두 메서드가 있다고 가정하자. 이때 두 메서드를 그대로 유지하는 것보다는 인수를 이용해서 다른 동작을 하도록 하나의 메서드로 합치는 것이 바람직할 수 있다(그러면 복사 및 붙여넣기를 하는 기법에 비해 프로그램이 짧고 간결해지며, 불필요한 에러도 줄일 수 있다.) 조금 경험이 있는 프로그래머라면 자바 8 이전 상황에서는 익명 클래스를 이용해서 동작 파라미터화를 구현할 수 있다고 생각 할 것이다. 

 

메서드에 코드를 전달(뿐만 아니라 결과를 반환하고 다른 자료구조로 전달할 수도 있음) 하는 자바 8 기법은 함수형 프로그래밍에서 위력을 발휘한다. 코드를 전달하거나 조합해서 자바의 강력한 프로그래밍 도구로 활용할 수 있다는 것을 이 책 전반에서 확인할 수 있다. 

 

1.1 절 : 자바가 멀티코어 병렬설(기존의 자바에서 부족했던 특성) 을 더 쉽게 이용할 수 있도록 진화하는 과정과 관련 개념을 설명한다. 

1.2절  : 자바 8에서 제공하는 코드를 메서드로 전달하는 기법이 어떻게 강력한 새로운 프로그래밍 도구가 될 수 있는지 설명한다. 

1.3절 : 스트림 API (병렬형 데이터를 표현하고 이들 데이터를 병렬로 처리할 수 있음을 유연하게 보여주는)가 어째서 강력하고 새로운 프로그래밍 도구인지 설명한다.

1.4절 : 디폴트 메서드라는 새로운 자바 8의 기능을 인터페이스, 라이브러리의 간결셩 유지 및 재컴파일을 줄이는 데 어떻게 활용할 수 있는지 설명한다. 

1.5절 : JVM을 구성하는 자바 및 기타 언어에서 함수형 프로그래밍이라는 존재가 어떤 영향을 미치는지 제시한다. 

 


스트림 처리

스트림이란 한번에  한 개씩 만들어지는 연속적인 데이터 항목들의 모임이다. 이론적으로 프로그램은 입력 스트림에서 데이터를 한 개씩 읽어 들이며 마찬가지로 출력 스트림으로 데이터를 한 개씩 기록한다. 즉, 어떤 프로그램의 출력 스트림은 다른 프로그램의 입력 스트림이 될 수 있다. 

728x90
728x90

안녕하세요, 늘 부족하고 배움을 갈구하는  2년차 백엔드 개발자 던킨 입니다. 

오늘 Modern Java in Action 책을 사고 읽으면서 좋은 내용들이 많아 리뷰를 하려고합니다.

많은 개발자 분들이 이미 이 책에 관련해서 리뷰와 함께 많은 리소스를 공유 해주었다고 해도 과언이 아니지만, 저 또한 이 책에 푹 빠져있는 독자로써

또한, 제 블로그를 찾아오시는분들을 위해 짧게 나마 잘 정리 해서 공유드리고 싶어 리뷰를 시작했습니다.  

 

 


'함수형 프로그래밍은 뭔가요?'

- 함수형 프로그래밍은 프로그래밍 기법을 지칭한다. 함수형 프로그래밍에서는 함수를 값으로 취급한다.

자바 8의 놀라운 점은 함수형 프로그래밍의 여러 장점을 친숙한 자바 문법으로 접목했다는 것이다. 훌룡한 자바 8의 설계 덕분에 함수형 프로그래밍을 자바 8에 새로 추가된 디자인 패턴 처럼 사용할 수 있으며 짧은 시간에 더 명확하고 간결한 코드를 구현할 수 있다. 프로그래밍 무기창고에 더  넓은 영역을 커버하는 무기가 추가되었다고 생각하면됩니다.

 

자바 8에 새롭게 추가된 핵심 기능뿐만 아니라 디폴트 메서드, 새로운 Optional 클래스, CompletableFuture, 새로운 날짜와 시간 API 등 유용한 기능도 설명한다.

 

자바 9에서는 새로운 모듈 시스템, Flow API 를 통한 리액티브 프로그래밍 지원 및 다양한 개선 기능이 추가되었다.

 

 

이 책은 크게 '기초', '함수형 데이터 처리', '스트림과 람다를 이용한 효과적 프로그래밍', '매일 자바와 함께', '개선된 자바 동시성', '함수형 프로그래밍과 자바의 미래' 여섯가지 내용으로 구성되었습니다. 

 

천천히 업로드 하면서 올릴 예정입니다.

아마 많은 SI 회사들은 아직 자바 8을 많이 사용한다고 알고있습니다.

대부분의 서비스 회사들은 자바 11과 스프링부트를 사용한다고 들었습니다(?? 맞는 정보인거죠?)

 

저는 금융권 관련해서 솔루션회사에서 업무를 진행하고 있으며 자바 8을 사용중에 있습니다.

저 같은 아직 신입은 이 책이 더더욱 중요하게 다가왔습니다. 혹시나 내가 이 책으로 인해서 회사에서 저의 코드가 조금 더 가치가 생길 수 있다 라는 희망을 품으면서 이 책을 읽고 있습니다.

 

 

728x90
728x90

개요

Elasticsearch 와 같은 분산형 시스템을 다룰 때 동시성 때문에 문제가 생길수 있습니다.

Elasticsearch는 어떻게 동시성 문제를 제어하는지에 대해 알아볼겁니다. 그 이전에 동시성 문제가 무엇인지 알아야합니다.

동시성 제어는 여러 클라이언트나 요청이 동시에 Elasticsearch 클러스터에 접근하거나 쓰기 작업을 수행할 때 데이터 무결성을 유지하고 성능을 최적화하기 위해 사용되는 중요한 개념입니다. 

 

  • 인덱스 동시성 - 여러 클라이언트가 동시에 같은 인덱스에 데이터를 쓰려고 할때, Elasticsearch 는 쓰기 작업을 조정하여 데이터 무결성을 보장합니다. 
  • 검색 동시성 - 많은 클라이언트가 동시에 검색을 실행할 때, Elasticsearch 는 검색 요청을 효율적으로 처리하기 위해 자원을 관리하고 검색 결과를 반환합니다. 
  • 노드간 동시성 - Elasticsearch  클러스터의 여러 노드 간에 데이터를 분산하고 복제할 때, 동시성을 관리하여 데이터 복제 및 복구 프로레스를 안정적으로 수행하빈다. 
  • Elasticsaerch 내부에서 자동으로 이루어지며, 사용자는 클라이언트 코드에서 추가적인 조치나 설정을 해야할 필요가 없습니다. 

 


1.1 동시성 제어

Elasticsaerch 는 분산 되어 있습니다. 문서가 생성, 업데이트 또는 삭제되면 새 버전의 문서가 클러스터의 다른 노드에 복제되어야합니다. 또한 비동기식 이며 동시에 진행되기 때문에 이러한 복제 요청은 병렬로 전송되며 순서가 맞지 않게 목적지에 도착할 수 있습니다.

 

Elasticsearch 는 문서의 이전 버전이 최신 버전을 덮어쓰지 않도록 보장하는 방법이 필요합니다.

 

문서의 이전 버전이 최신 버전을 덮어쓰지 않도록 하기 위해, 문서에 대해 수행되는 모든 작업에는 해당 변경을 조정하는 기본 샤드에 의해 시퀀스 번호가 할당됩니다. 

시퀀스 번호는 각 작업에 따라 증가하므로 최신 작업은 이전 작업보다 더 높은 시퀀스 번호를 갖도록 보장됩니다. 

그러면 Elasticsearch 는 작업의 시퀀스 번호를 사용해 더 작은 시퀀스 번호가 할당된 변경으로 인해 최신 문서 버전이 재저으이되지 않도록 할 수 있습니다. 

1.1-1 동시성 제어 목적

 일관성 보장  여러 클라이언트 또는 스레드가 동시에  Elasticsearch 에 데이터를 쓰거나 숮어할 때 데이터 일관성을 보장합니다. 동시성에 제어를 통해 충돌이나 데이터 손실을 방지합니다. 
지원관리  Elasticsearch 클러스터는 제한된 자원 ( 예: CPU, 메모리 , 디스크 공간) 을 가지고 있습니다. 동시성 제어를 사용하여 자원 사용을 효율적으로 관리하고 과부하를 방지합니다. 
성능 향상 동시성을 관리하면 다수의 동시 요청에 대한 대기 시간을 최소화하고 응답 시간을 개선할 수 있습니다. 
Elasticsearch 에서 동시성 제어는 다음과 같은 방법으로 구현됩니다.
Elasticsearch 에서 동시성 제어는 다음과 같은 방법으로 구현됩니다. 
REST API 제한  Elasticsearch 는 RESTful API 를 통해 상호 작용하며, 클라이언트가 요청을 전송할 때 병렬로 실행될 요청의 수를 제한하는 설정을 가질 수 있습니다. 이를 통해 과도한 요청이 동시에 처리되지 않도록 제어할 수 있습니다.
스레드 풀 제어 Elassticsearch 는 내부적으로 스레드 풀을 사용하여 요청을 처리합니다. 스레드 풀 설정을 통해 동시 처리 스레드 수를 제한하거나 조절할 수 있습니다. 
버퍼링과 큐  Elasticsearch 클라이언트와 서버 간의 요청과 응답은 버퍼링되고 큐잉 될수 있습니다. 이를 통해 요청이 서버로 전달되기 전에 대기하게 하거나 과부하 상태일때 대기열에서 처리 순서를 조절할 수 있습니다. 
릴리스 및 재시도 매커니즘  Elasticsearch 클라이언트는 요청이 실패할 경우 자동으로 재시도할 수 있는 매커니즘을 가지고 있습니다. 이를 통해 네트워크 문제 또는 일시적이 ㄴ오류로 인해 요청이 실패한 경우에 대처할 수 있습니다.

 

예시 ) 전자 상 거래 애플리케이션

웹사이트 방문자가 장바구니에 상품을 추가하고 결제를 완료했다고 가정해 보겠습니다. 

그런 일이 발생하면 애플리케이션은 Elasticsearch 에서 제품을 검색합니다. 

이 특정 시점에 다른 방문자가 동일한 제품에 대한 결제 플로우를 완료하고 동일한 제품에 대한 결제 flow 를 완료하고 웹 서버의 다른 스레드에서도 제품을 검색합니다. 이시쯤 에서 두 스레드 모두 동일한 제품을 검색했습니다. 

 

 

 

이러한 결과는 애플리케이션에 따라 다르지만 이 경우 다음과 같은 결과가 발생할 수 있습니다. 

재고가 없는 제품을 판매하여 고객 겸험이 나빠지게 되는것이 있습니다.

 

이러한 경우 어떻게 해야 일이 발생하지 않을 수 있을까요??


문서를 검색한 이후 수정된 경우 업데이트가 실패하지 않도록 해야합니다. 버전관리가 이때 필요한것이겠죠 

 _seq_no 와 _primary_term 처럼 동시성을 제어하기 위한 메타데이터로 모든 문서마다 붙는다.
 _versio은 0 이상 long 범위 이내의 정수여야 한다.
 _seq_no, _primary_term과 다른 점은 클라이언트가 문서의 _version 값을 직접 지정할 수 있다.
◦현재 버전값보다 낮은 값으로 색인할 수 없다.
version_type을  external(external_gt)이나 external_gte로 설정하면 클라이언트가 직접 _version을 지정할 수 있다.

  defual version_type 은 internal

다른 스토리지에서 저장된 데이터의 버전을 따로 관리하고 있고 그 데이터를 엘라스틱서치로 받아 와서 2차 스토리지로 동기화하여 사용하는경우 활용하기 좋다.

코드 > 

예시) 인덱싱 명령은 문서를 만들고 할당합니다. 초기 시퀀스 번호 및 기본용어

응답 및 필드에서 할당된 시퀀스 번호와 기본 항을 볼 수 있습니다. _seq_no, _primary_term

Elasticsearch는 저장된 각 문서를 변경한 마지막 작업의 시퀀스 번호와 기본 용어를 추적합니다. 시퀀스 번호와 기본 용어는 GET API의 응답에서 _seq_no _primary_term 필드에 반환됩니다

반환 값

참고: 검색 API는 seq_no_primary_term 매개변수를 설정하여 각 검색 히트에 대해 _seq_no 및 _primary_term을 반환할 수 있습니다.

 

시퀀스 번호와 주 용어는 변경 사항을 고유하게 식별합니다. 반환된 시퀀스 번호와 기본 용어를 기록해 두면 검색 이후 문서에 다른 변경 사항이 없는 경우에만 문서를 변경할 수 있습니다. 이 작업은 인덱스 API, 업데이트 API 또는 삭제 API의 if_seq_noif_primary_term 매개변수를 설정하여 수행합니다.

 

예를 들어, 다음 인덱싱 호출은 설명이 변경되거나 다른 API에 의해 다른 태그가 추가될 수 있는 가능성을 잃지 않고 문서에 태그를 추가합니다:

728x90
728x90

Runnable 인터페이스로 다른 스레드에서 코드를 실행하는 방법과 진해지는 정도의 수준.

그리고 스레드 클래스의 유용한 기능을 알아보고 IDE를 사용해 스레드를 디버그 하는 법도 해볼게요. 

1. 스레드 생성하는 방법 

Java 에서는 JDK 가 모든 스레드의 관련 속성과 메서드를 스레드 클래스로 압축합니다. 

그래서 새 스레드를 만들려면 새 스레드 객체부터 생성해야하죠!! 스레드 객체 자체는 기본적으로 비어있스빈다. 

그러니 runnable 인터페이스를 구현하는 클래스의 객체를 해당 생성자에 전달해야합니다. 

run 메서드에 어떤 코드를 넣든 운영 체제가 스케줄링하자마자 새 스레드에서 실행될 겁니다. 

자바 8부터는 람다로 줄일수 있죠?!?! 

 

스레드 객체에서 start 메서드를 호출해 스레드를 시작해야합니다. 

 

그럼 JVM이 새 스레드를 생성해 운영 체제에게 전달합니다. 

스레드 클래스에는 유용한 메서드가 몇가지 있습니다. 

예를 들어, start 메서드를 호출 전에 log line을 추가해 현재 실행중인 스레드를 출력하려면 thread.currentThread라는 정적 메서드를 호출해 현재 스레드의 스레드 객체를 알아내야합니다. 스레드 객체를 얻으면 getName메서드나 getId 메서드를 사용할 수 있는데 getName을 사용하겠습니다. 

스레드 클래스에는 sleep 메서드라는 정적 메서드도 있습니다. 아시겠지만, 이 메서드는 현재 스레드를 주어진 밀리초 만큼 멈추게 합니다. 

이건 반복되는 명령문이 아닙니다. sleep 메서드는 운영 체제에게 지시하는것 뿐입니다. 이 시간이 지날때까지는 현제 스레드를 스케줄링을 하지말라는거죠, 이 스레드는 이 시간 동안 cpu를 쓰지 않는겁니다. 

이제 run 메서드에 코드를 추가해 새 스레드에서 실행해 볼게요.

밑에 사진에서 처럼 main이라는 이름의 스레드 객체가 반환됐습니다. 메인 스레드가 실행되었다는거죠 그리고 start 메서드를 호출한 뒤의 새 스레드는 스케줄링 되지 않았어요 시간이 걸리니깐요 운영 체제에 의해 비동기적으로 발생하죠! 

따라서 두 번째 출력문도 main 스레드 입니다. 그 후에 thread-0 이라는 새 스레드 코드가 실행되어 반환이 된거죠.

이 스레드 생성 방법을 통해서 생성법을 알았으니 스레드 클래스를 이용한 응용 기능들을 배워 봅시다. 

우선 JVM 이 새 스레드에 Thread-0 이라는 쓸모 없는 이름이 붙었었죠????

현재 는 괜찮을지도 모르지만 스레드 개수가 많은 어플리케이션을 만들었을때는 스레드의 의미 있는 이름이 추후 디버깅에 큰 도움이 될겁니다.  

스레드 이름을 설정하기 위해 thread.setName 메서드를 호출해 new worker thread 라고 붙이고 어플리케이션을 다시 실행하면 이렇게 새 이름이 콘솔에 출력되게 됩니다.

이전 lecture에서 운영체제가 각 스레드에 동적 우선순위를 적용하는 방법을 배웠습니다. 따라서 스레드 객체를 사용하면 동적 우선순위의 정적 요소를 계획적으로 설정할수 있습니다. setPriority 메서드를 호출해 1부터 10까지의 값을 주거나 사전 정의된 값인 maxPriority, minPriority 아니면 normPriority도 쓸수 있습니다. 전 maxPriority를 사용하겠습니다. 

설정을 유효화하기 위해 새 스레드에 출력 제어문을 더해 우선순위가 설정됐음을 명시합니다. 그러려면 현제 스레드 객체에 getPriroity 메세드를 호출해야합니다.  이제 스레드의 우선순위를 봅시다. 

MAX priroty를 사용했지만 동작에는 차이가 없습니다. 하지만 복잡한 프로그램의 스레드가 보다 많은 응답성을 필요로 하면 아주 중요한 역할을 합니다. 

이제 IDE에서 멀티스레드 애플리케이션을 시각적으로 디버그해 볼게요. 

"before start a new thread" 전에 첫 중단점이 뜹니다. 

디버그 창으로 가서 스레드 탭을 열면 현재 JVM에서 실행 중인 모든 스레드와 스택 추적을 확인할수 있습니다. 

또, 현재 실행중인 메인 스레드와 JVM 이 생성한 새게의 스레드는 당정 제어할 수 없다는것도 확인이 가능합니다. 

이대로  계속해서 다음 중단점으로 보면 493이라는 ID이라는 "new worker thread"가 실행중인것을 알수 있습니다.

메인 스레드와 "new worker thread"가 동시에 실행되고 있는걸 알수 있습니다. 

breakerPointer = 중단점)

중단점을 지정할 때마다 모든 스레드가 동결되고 개별적으로 검사할 수 있다는 뜻입니다. 

새 스레드에 다른 중담점을 추가한 후 계혹한다면 메인스레드는 이미 완료됐고 JVM이 파기했다는걸 알수있습니다. 

 

보통 Java 에서 체크되지 않은 예외는 우리가 직접 캐치해서 특정 방법으로 처리하지 않으면 전체 스레드를 다운시킵니다. 

 

thread.setUncauhtExceptionHandler();

위에 구문을 통해서 처음부터 전체 스데르에 해당되는 예외 핸들러를 지정할 수 있습니다. 

스레드 내에서 발생한 예외가 어디서도 캐치되지 않으면 핸들러가 호출될 겁니다. 그러면 우리는 채키되지 않은 스레드와 

예외를 출력하기만 하면됩니다. 하지만 더 현실적으로 리소스 일부를 정리한다거나 추가 데이터를 로그하면 문제가 발생한 이후에 우리가 해결할 수 있습니다. 이를 구현하기 위해 스레드에 적절한 이름을 붙이고 RuntimeException을 내부 메시지와 throw 합니다. 

이대로 프로그램을 실행하면 Misbehaving thread에서  Intentional Exception이라는 에러 메시지가 발생했다고 뜹니다. 

 

728x90

+ Recent posts