return
문을 만나면 실행을 종료한다.메인 스레드 외에 스레드를 작업 스레드라고 한다. 이 작업 스레드를 생성하기 위해서는 두 가지 방법이 있다.
여기서 중요한 점은 둘 다 run()
메서드를 구현해야 한다는 것이다.
class Test01 implements Runnable {
public void run() {
...
}
}
class Test02 extends Thread {
public void run() {
...
}
}
Thread를 상속받아 1개 생성
Runnable 구현하여 1개 생성
외부 클래스로 스레드 2개, 내부 클래스로 스레드 2개, 익명 구현 객체로 1개 생성 -> 총 5개의 스레드를 실행하는 예제
실행 결과는 매번 다르기 때문에 단정 지을 수 없다. 대부분 1 2 3 4 5 가 나오겠지만 그렇지 않을 수도 있다. 이는 스레드를 실행하는 데 우선순위가 정해져 있지 않기 때문이다.
main
이라는 이름을 가진다.Thread-n
이라는 이름을 가진다.getName()
메서드와 setName()
메서드로 스레드의 이름을 조회하고 설정할 수 있다.currentThread()
를 사용하면 스레드의 주소값을 얻을 수 있다.즉, 임계 영역으로 설정된 객체가 다른 스레드에 의해 작업이 이루어지고 있지 않을 때, 임의의 스레드 A는 해당 객체에 대한 락을 획득하여 임계 영역 내의 코드를 실행할 수 있다.
스레드 A가 임계 영역 내의 코드를 실행 중일 때, 다른 스레드들은 락이 없으므로 임계 영역 내의 코드를 실행할 수 없게 된다.
스레드 A의 코드 실행이 끝나면 락을 반납하고 이때부터 다른 스레드들 중 하나가 락을 얻어서 임계 영역 내의 코드를 실행할 수 있게 된다.
특정 코드 구간을 임계 영역으로 설정하기 위해서는 synchronized
키워드를 사용한다.
synchronized
키워드를 사용하는 방법은 두 가지가 있다.
public synchronized void test() {
...
}
synchronized
옆 소괄호 안에는 해당 영역이 포함된 객체의 참조를 넣으면 된다.public void test() {
synchronized (...) {
...
}
}
JVM의 동작 방식은
이 때 실행 엔진은 두 가지 방식으로 바이트 코드를 실행시킨다.
인스턴스를 생성하면 Heap 영역에 인스턴스가 생성되며, 인스턴스가 생성된 위치의 주소값을 참조 변수에 할당해주는데, 이 참조 변수는 Stack 영역에 선언된 변수이다.
가비지 컬렉션의 동작 방식을 이해하려면 Heap 영역에 대한 이해가 필요하다.
JVM의 Heap 영역의 객체는 대부분 일회성이며, 메모리에 남아 있는 기간이 대부분 짧다는 전제로 설계되어 있다.
그렇기 때문에 이 객체가 얼마나 살아있냐에 따라서 Heap 영역을 Young, Old 영역으로 나눈다.
Young 영역은 새롭게 생성된 객체가 할당되는 곳이고 이곳에서 많은 객체가 생성되었다 사라지는 것을 반복한다.
이 영역에서 활동하는 가비지 컬렉터를 Minor GC라고 한다.
Young 영역에서 살아남은 객체들이 Old 영역으로 복사된다. 보통 Young 영역보다 크게 할당되고 크기가 큰 만큼 가비지는 적게 발생한다.
이 영역에서 활동하는 가비지 컬렉터를 Major GC라고 한다.
가비지 컬렉션가 실행될 때는 두 가지 단계를 따른다.
Stop The World
Stop The World는 가비지 컬렉션을 실행시키기 위해 JVM이 애플리케이션의 실행을 멈추는 작업이다.
가비지 컬렉션이 실행될 때 가비지 컬렉션을 실행하는 스레드를 제외한 모든 스레드들의 작업이 중단되고, 가비지 정리가 완료되면 재개된다.
Mark and Sweep
Mark는 사용되는 메모리와 사용하지 않는 메모리를 식별하는 작업을 의미한다. Sweep은 Mark 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업을 의미한다.
즉, 1번을 통해 모든 작업이 중단되면, GC가 모든 변수와 객체를 탐색해 각각 어떤 객체를 참고하고 있는지 확인한다.
그리고, 사용되고 있는 메모리를 식별해 사용되지 않는 메모리는 제거하는 과정을 진행한다.