들어가며
이번 포스트에서는 스레드에 대한 포스트 입니다.
사실 한번쯤은 모두 공부해본 내용이지만 , 정리도하고 java에서는 어떻게 활용할 수 있는지에 대한 이야기도 함께 하겠습니다.
스레드?
프로세스 내에서 실행되는 독립적인 작업 단위이며 여러 스레드가 하나의 프로세스에서 동작할 수 있습니다.
그리고 스레드는 자체적인 흐름제어,스택,레지스터를 가지고 있습니다.
사용하는 가장 큰 이유는 여러 작업을 동시에 수행하여 효율성을 높이기 위해 사용합니다.
자바에서 스레드 쓰기
- Thread 클래스 상속: Thread 클래스를 상속받고 run() 메서드를 오버라이딩하여 스레드의 실행 코드를 구현합니다.
- Runnable 인터페이스 구현: Runnable 인터페이스를 구현하고 run() 메서드를 오버라이딩하여 스레드의 실행 코드를 구현합니다.
개발자가 스레드를 쓸 수 있는 방법은 크게 두 가지 입니다.
public class ThreadExample {
public static void main(String[] args) {
// Thread 클래스 상속
Thread thread1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread 1: " + i);
}
}
};
// Runnable 인터페이스 구현
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread 2: " + i);
}
}
});
thread1.start();
thread2.start();
}
}
코드를 보면 위 언급한 두가지 방법을 통해 구현했습니다.
단순히 0 ~ 9 까지 출력하는 예제 입니다.
실행 해보면 결과가 다음과 같습니다.
순서대로 나오지 않고 , 섞여 있는 모습을 볼 수 있는데 스레드를 생성해 동시에 작업을 진행하였기 때문입니다.
그럼 현실 , 즉 메모리에서는 어떻게 동작 하는지에 대해서도 궁금한데요
스레드가 사용하는 메모리
영역 내용 공유 여부
스택 | 스레드 실행 흐름, 로컬 변수, 메서드 호출 정보 | X (각 스레드마다 독립적) |
힙 | 스레드가 사용하는 객체 | O (모든 스레드가 공유) |
프로그램 카운터 | 현재 실행 중인 명령어 | X (각 스레드마다 독립적) |
레지스터 | CPU 임시 저장 공간 | X (각 스레드마다 독립적) |
각 스레드는 독립된 개체로써 사용하기 때문에 각각의 제어,스택,레지스터를 가지고 있습니다.
저는 이렇게 이해했는데요
공간(레지스터)에 실행 중인 명령(프로그램 카운터)과 스레드 마다 가진 데이터(스택) 스레드가 공유하는 데이터-객체(힙)
궁금증이 생긴 것은 static 영역은 그럼 스레드를 사용할 때는 사용하지 않는지에 대해 알아보고 싶어졌습니다. 그래서 찾아보니 다음과 같습니다.
static은 안쓰니?
일반적으로는 static 영역을 쓰지 않는다.
왜? static 영역을 사용하면 모든 스레드가 공유되고 , 이는 독립성의 문제를 발생시킵니다.
또한, 동기화 기술을 자체적으로 사용해야만 하며
( 데이터 손상에 대한 고려) static영역은 전 포스트에서 이야기했던것처럼
프로그램이 시작되고 종료될때까지 유지되기 때문에 메모리의 누수 즉, 굳이 안쓰는 공간을 비효율적으로 차지할 수 있습니다.
정리하면 다음과 같습니다.
- 독립적인 실행 흐름: 스레드는 각자의 실행 흐름을 가지고 있어야 하며, static 영역은 모든 스레드가 공유하기 때문에 스레드 간의 독립성을 유지하기 어렵습니다.
- 변수의 동기화 문제: static 변수는 모든 스레드가 공유하기 때문에 동기화 기술을 사용하지 않으면 데이터 손상이 발생할 수 있습니다.
- 메모리 누수 가능성: static 영역은 프로그램 종료 시까지 메모리에 존재하기 때문에 스레드에서 사용하지 않는 static 변수가 메모리 누수를 유발할 수 있습니다.
물론 무조건 쓰지 못하게 막은 것은 아닙니다.
예를 들어 모든 스레드가 공유하는 상수값, 클래스 변수를 저장 할 때는 static영역을 활용할 수 있다고 합니다.
다만 이 경우에도 동기화 기술을 사용해야 한다고 합니다.
레지스터는 뭔데?
레지스터는 CPU 내부에 있는 작고 빠른 메모리 공간입니다. CPU는 레지스터를 사용하여 계산, 데이터 비교, 논리 연산 등을 수행하는데 필요한 데이터와 명령어를 임시적으로 저장합니다.
레지스터의 특징:
- 빠른 속도: 레지스터는 CPU 내부에 위치하기 때문에 메모리보다 훨씬 빠른 속도로 접근할 수 있습니다.
- 작은 크기: 레지스터는 메모리보다 훨씬 작은 크기입니다.
- 다양한 종류: 레지스터는 다양한 종류가 있으며, 각각 다른 용도로 사용됩니다.
레지스터의 용도:
- 계산: 레지스터는 덧셈, 뺄셈, 곱셈, 나눗셈 등의 계산에 필요한 데이터를 저장합니다.
- 논리 연산: 레지스터는 AND, OR, NOT 등의 논리 연산에 필요한 데이터를 저장합니다.
- 명령어 저장: 레지스터는 다음에 실행할 명령어를 저장합니다.
레지스터의 종류:
- 일반 레지스터: 일반적인 계산 및 데이터 저장에 사용됩니다.
- 특수 레지스터: 프로그램 카운터, 스택 포인터 등 특정 용도로 사용됩니다.
레지스터의 중요성:
레지스터는 CPU의 성능에 중요한 영향을 미칩니다. 레지스터의 크기와 속도가 클수록 CPU는 더 빠르게 프로그램을 실행할 수 있습니다.
정리
이번 포스트는 자바에서 스레드를 어떻게 쓰고 , 동작하는지에 대해 알아봤습니다.
스레드 라는 개념은 자주 들어서 인지하고 있었는데 정리해보며 알아봤습니다.
이번 포스트를 쓰며 @overriding 이라는 어노테이션을 사용하였는데
오버로드와 오버 라이딩에 대해서도 정리해보자고 생각이 들어 다음은
관련된 내용을 포스트하겠습니다.
'JAVA' 카테고리의 다른 글
JAVA - OOP 실사용 (0) | 2024.05.29 |
---|---|
JAVA-OverLoding & OverRiding (0) | 2024.05.29 |
JAVA- 메모리 (0) | 2024.05.28 |
JAVA - 구동과정 (0) | 2024.05.27 |
JAVA -객체 와 동작 (0) | 2024.05.27 |