Java

[JAVA] 13. 쓰레드(Thread)

히비스 2021. 5. 4. 12:24

쓰레드는 언제 수행 되는가?

java 명령어를 사용하여 클래스를  실행시키는 순간 자바 프로세스가 시작되고,

main() 메소드가 수행되면서 하나의 쓰레드가 시작된다.

 

※아무런 쓰레드를 생성하지 않아도, JVM을 관리하기 위한 여러 쓰레드가 존재한다.

예를 들면 자바의 쓰레기 객체를 청소하는 GC 관련 쓰레드처럼 말이다.

 

 

쓰레드는 왜 만들었을까?

프로세스가 하나 시작하려면 많은 자원이 필요함.

만약 하나의 작업을 동시에 수행하려고 할 때 여러 개의 프로세스를 띄워서 실행하면 각각 메모리를 할당해야 함.

JVM은 기본적으로 적어도 32MB~64MB의 물리 메모리를 점유함.

그에 반해, 쓰레드를 하나 추가하면 1MB 이내의 메모리를 점유함. (쓰레드 == 경량프로세스)

 

 

쓰레드는 어떻게 생성하는가?

크게 두 가지 방법이 있음.

1. Runnable 인터페이스 사용

Runnable 인터페이스를 구현

 

2. Thread 클래스 사용

Thread 클래스를 확장

 

 

각각 하나씩 시작

 

 

둘은 언제 구분하여 사용해야 하는가?

자바에서 Thread 클래스를 확장 받아야만 쓰레드로 구현할 수 있는데, 다중 상속이 불가하므로

해당 클래스를 쓰레드로 만들지 못함.

하지만, 인터페이스는 여러 인터페이스를 구현해도 상관없음.

 

정리하자면, 쓰레드 클래스가 다른 클래스를 확장할 필요가 있을 경우에는 Runnable 인터페이스를 구현.

그렇지 않은 경우엔 쓰레드 클래스를 사용하면 된다.

 

start() 메소드를 호출하면, 쓰레드 클래스에 있는 run() 메소드의 내용이 끝나든, 끝나지 않든 간에

쓰레드를 시작한 메소드에서는 그 다음 줄을 실행한다.

 

새로 생성한 쓰레드는 run() 메소드가 종료되면 끝난다.

 

 

 

쓰레드를 시작할 때 어떤 값을 전달하고 싶으면

calcNumber라는 값을 동적으로 지정하여 쓰레드를 시작할 수 있다.

 

 

 

데몬 쓰레드란?

일반 쓰레드는 JVM이 해당 쓰레드가 끝날 때까지 기다린다고 했다.

데몬 쓰레드는 그 쓰레드가 수행되고 있든, 수행되지 않고 있든 상관 없이 JVM이 끝날 수 있다.

 

 

선언

 

필요성

모니터링하는 쓰레드를 별도로 띄워 모니터링하다가,

주요 쓰레드가 종료되면 관련된 모니터링 쓰레드가 종료되어야 프로세스가 종료될 수 있다.

그런데, 모니터링 쓰레드를 데몬 쓰레드로 만들지 않으면 프로세스가 종료될 수 없다.

이렇게 부가적인 작업을 수행하는 쓰레드를 선언할 때 데몬 쓰레드를 만든다.

 

 

 

쓰레드와 빠질 수 없는 synchronized

어떤 클래스나 메소드가 쓰레드에 안전(Thread safe)하려면, synchronized를 사용해야만 한다.

synchronized라는 단어만 넣어주면 된다.

이 메소드에 2개의 쓰레드가 접근하든, 100개의 쓰레드가 접근하든 간에 한 순간에는 하나의 쓰레드만 이 메소드를 수행하게 된다.

다시 말해, amount에 값을 더하고 있는 시점에 다른 쓰레드가 이 메소드 연산에 접근하지 못한다는 것이다.

 

 

성능상 문제 없게끔 synchronized 사용하기

어떤 클래스에 30줄짜리 메소드가 있다고 가정.

그 클래스에도 amount라는 인스턴스 변수가 있고, 30줄짜리 메소드에서 amount라는 변수를 한 줄에서만 다룬다.

만약 해당 메소드 전체는 synchronized로 선언한다면, 나머지 29줄의 처리를 할 때 필요 없는 대기 시간이 발생함.

이러한 경우에는 amount라는 변수를 처리하는 부분만 synchronized 처리를 해주면 된다.

 

lock이라는 객체는 하나의 문지기 역할

 

 

쓰레드와 연관있던 String 클래스들

StringBuffer와 StringBuilder라는 클래스가 있었다.

StringBuffer는 쓰레드에 안전하고,

StringBuilder는 쓰레드에 안전하지 않다.

 

StringBuffer는 synchronized 블록으로 주요 데이터 처리 부분을 감싸 두었고,

StringBuilder는 synchronized 라는 것이 사용되지 않았다.

 

따라서,

StringBuffer는 하나의 문자열 객체를 여러 쓰레드에서 공유해야 하는 경우에만 사용하고,

StringBuilder는 여러 쓰레드에서 공유할 일이 없을 때 사용하면 된다.

 

 

 

 

'Java' 카테고리의 다른 글

[JAVA] 중간 점검  (0) 2021.05.17
[JAVA] 14. Function Interface  (0) 2021.05.11
[JAVA] 12. 자바 컬렉션(Map편)  (0) 2021.04.30
[JAVA] 11. 자바 컬렉션(Set과 Queue편)  (0) 2021.04.30
[JAVA] 10. 자바 컬렉션(List편)  (0) 2021.04.30