일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 파이썬
- 프로그래밍
- web
- 자바
- 웹
- Database
- 서블릿
- 메소드
- Programming
- Python
- 프론트엔드
- 코딩
- frontend
- 함수
- 자바스크립트
- HTML
- String
- 문자열
- PL/SQL
- 오라클
- Method
- Servlet
- It
- 데이터베이스
- oracle
- JavaScript
- SQL
- java
- jsp
- function
- Today
- Total
Untitled_Blue
[JAVA] 쓰레드 (Thread) 본문
안녕하세요. 이번 글은 Thread에 대한 설명입니다.
- 쓰레드 (Thread)란?
- CPU를 사용하는 최소 단위
- 하나의 프로그램 실행 단위인 프로세스를 세분화해서 사용할 수 있는 단위
- 단일 쓰레드 기준 각 작업을 순차적으로 처리
+ 프로그램, 프로세스, 쓰레드의 차이
- 프로그램 (Program) : 실행 중이지 않고 설치만 되어있는 파일
- 프로세스 (Process) : 메모리 상 로딩 중이며 실행 중인 프로그램
- 쓰레드 (Thread) : 프로세스를 처리하기 위한 CPU를 사용하는 최소 단위
- 멀티 쓰레드
- 하나의 프로세스 내에 2개 이상의 쓰레드가 동작하는 과정
쓰레드 하나를 일꾼이라고 생각해보자. 하나의 프로세스 안에 일꾼이 두 명 이상이 존재한다는 뜻이다. 프로세스에 대한 작업을 여럿이서 분담하기 때문에 한 명일 때보다 작업의 효율성이 증가하고 멀티 프로세스 (프로그램을 두 개 이상 실행하는 행위)보다 상대적으로 메모리 사용량이 적다. 적은 자원 사용으로 최대의 효율을 내는 효과가 있다. 또한 한 곳에서 두 개 이상의 결과를 같은 타이밍에 송출해야 하는 상황도 멀티 쓰레드를 사용한다.
+ 멀티 쓰레드의 조건
- 동시성 : 매우 짧은 간격으로 교차 실행되는 방식 (동시에 실행되는 것 X, 동시 실행되는 것처럼 보이는 것 O)
- 병렬성 : CPU 내 각각의 작업을 각각의 코어에 할당해서 동시에 실행하는 방식
- Thread 생성 및 실행
1) Thread 생성 및 실행
package classes;
class Sampling extends Thread { // 쓰레드 상속
@Override
public void run() {
System.out.println("Thread Run...");
}
}
public class Thread_Practice {
public static void main(String[] args) {
Sampling sm = new Sampling();
sm.start(); // Thread Run...
}
}
쓰레드는 기본적으로 별도의 클래스를 생성한 후 추가적으로 extends Thread를 통해 쓰레드를 상속받는 것으로부터 시작한다. 이후 메인 메서드에서 쓰레드를 상속받은 클래스에 대한 객체를 생성한 후 객체를 통해 오버라이딩한 start() 메서드를 호출해서 쓰레드를 실행한다.
2) 멀티 쓰레드 실행
- Thread 상속을 통한 멀티 쓰레드 구현
package classes;
class Sampling extends Thread { // 쓰레드 상속
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < 5; i++) {
System.out.println("Second Thread : " + (i + 1));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Thread_Practice {
public static void main(String[] args) {
Sampling sm = new Sampling();
sm.start();
for (int i = 0; i < 5; i++) {
System.out.print("First Thread : " + (i + 1) + " and ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
이때 멀티 쓰레드는 서로 독립적으로 실행하기 때문에 Second Thread가 뒤에 출력되도록 하기 위해 run() 이전에 0.01초를 설정했다. 독립적이라는 점은 곧 서로가 별도의 개념이기 때문에 엇박자가 발생할 수도 있다는 뜻이다.
- Runnable 인터페이스 상속을 통한 구현
package classes;
class Sampling implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.print("First Thread : " + (i + 1) + " and ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Thread_Practice {
public static void main(String[] args) {
Runnable runnable = new Sampling();
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < 5; i++) {
System.out.println("Second Thread : " + (i + 1));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
※ 결과는 상단의 Thread를 상속한 결과와 동일하다.
상단의 소스코드는 Thread 클래스를 상속받는 대신 인터페이스 Runnable를 상속받아서 구현한 멀티 쓰레드이다.
- 클래스에 implements Runnable를 사용해서 run() 메서드를 오버라이딩을 받고 내부에 구현할 코드를 작성한다.
- 이후 메인 메서드 안에 상속받은 클래스를 사용하기 위해 Runnable를 통해 객체를 생성한다.
- 이때 Runnable 인터페이스 안에는 start() 메서드가 존재하지 않기 때문에 별도로 Thread에 대한 객체를 생성해주고 소괄호 안에 실행할 주체인 Runnable의 객체를 매개변수로서 넘겨줘야 한다.
- Thread의 객체를 사용해서 start() 메서드를 호출해서 쓰레드를 실행한다.
- 쓰레드에 관한 메서드
메서드 | 설명 |
.start() | 쓰레드 시작 |
.getName() | 쓰레드의 이름 반환 |
.setName(String name) | 쓰레드의 이름 설정 |
.isAlive() | 쓰레드의 실행 중에 대한 여부 반환 (Boolean 형 반환) |
.run() | 쓰레드 실행 시 구현한 로직 작성 |
.sleep(long milis) | 밀리초동안 쓰레드 일시정지 (= 대기) |
.getState() | 쓰레드의 현재 상태 반환 |
.currentThread() | 현재 실행 중인 쓰레드에 대한 참조값 반환 |
.join() | 쓰레드가 종료될 때까지 대기 |
.getPriotity() | 쓰레드에 대한 우선순위 반환 |
.setPriortity(int p) | 쓰레드에 대한 우선순위 설정 |
.interrupt() | 쓰레드를 안전하게 종료 (InterruptedException 예외 발생) |
.interrupted() | 쓰레드의 안전 종료 여부 반환 (Boolean 형 반환) |
이외에도 자바 공식 API 문서에 더 많은 메서드와 생성자가 있다. 그중에서도 stop(), resume(), suspend()과 같은 문제가 많은 메서드는 Deprecated. 더 이상 사용 또는 지원되지 않는다는 점을 확인할 수 있다.
package classes;
class Sampling extends Thread {
Thread thread = new Thread();
@Override
public void run() {
int cnt = 0;
System.out.println("Thread Name : " + thread.getName());
System.out.println("Thread ID : " + thread.getId());
System.out.println("Thread Priority : " + thread.getPriority());
System.out.println("Thread isAlive : " + thread.isAlive());
System.out.println("Thread isInterrupted : " + thread.isInterrupted());
while (true) {
System.out.println("Thread : " + (cnt + 1));
cnt++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (cnt >= 10) {
System.out.println("Thread Interrupt");
thread.setName("This is Thread !");
thread.interrupt();
break;
}
}
System.out.println("Thread Name : " + thread.getName());
System.out.println("Thread isAlive : " + thread.isAlive());
System.out.println("Thread isInterrupted : " + thread.isInterrupted());
}
}
public class Thread_Practice {
public static void main(String[] args) {
Sampling sm = new Sampling();
sm.start(); // 쓰레드 시작
}
}
상단 소스코드를 실행한 결과 상단 이미지와 같이 쓰레드가 순차적으로 출력되다가 cnt 수가 10이 되면서부터 Interrupt()를 실행함으로써 중단되는 것을 확인할 수 있다. 또한 쓰레드의 동작여부를 시작 전과 후를 통해 정상적으로 출력됨과 쓰레드가 중단되기 직전에 setName()으로 쓰레드의 이름을 설정해줌으로써 설정 전과 후 또한 달라졌음을 확인할 수 있다.
System.out.println("Thread currentThread : " + Thread.currentThread());
// Thread currentThread : Thread[Thread-0,5,main]
또한 현재 실행 중인 쓰레드에 대한 참조값도 확인해볼 수 있다.
package classes;
class Sampling extends Thread {
int mili = 0;
Sampling (int mili) {
this.mili = mili;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(mili);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Thread_Practice {
public static void main(String[] args) throws InterruptedException {
Sampling sm = new Sampling(3000);
Thread thread = new Thread(sm);
thread.start();
thread.join();
System.out.println("쓰레드가 종료되었습니다 !");
}
}
다음 소스코드는 .join()을 통해 쓰레드를 종료하는 과정을 보여주고 있다. 쓰레드가 시작되고 쓰레드 내 모든 과정이 끝나고 완전히 종료될 때까지 대기하다가 출력문이 나옴으로써 .join() 메서드가 쓰레드가 완전히 종료될 때까지 대기하는 점을 확인할 수 있다.
package classes;
class Sampling extends Thread {
int mili = 0;
Sampling (int mili) {
this.mili = mili;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + Thread.currentThread().getState());
try {
Thread.sleep(mili);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Thread_Practice {
public static void main(String[] args) throws InterruptedException {
Sampling sm = new Sampling(3000);
Thread thread = new Thread(sm);
System.out.println(thread.getName() + " : " + thread.getState());
thread.start();
thread.join();
System.out.println(thread.getName() + " : " + thread.getState());
System.out.println("쓰레드가 종료되었습니다 !");
}
}
상단의 소스코드를 통해 쓰레드의 현재 상태를 실행 중에 실시간으로 확인할 수 있다. 쓰레드가 생성되면 NEW, 작동 중이면 RUNNABLE, 종료되었으면 TERMINATED 상태가 나온다는 점을 알 수 있다. 이 외에도 일시정지 중이면 WAIT, BLOCKED, TIMED_WAITING의 상황별로 세 가지 중 하나가 나온다.
다소 부족하지만 쓰레드에 대한 기본적인 설명을 마치겠습니다.
다음 글은 JDBC에 대한 설명입니다. 감사합니다.
'Programming Language > JAVA' 카테고리의 다른 글
[JAVA] JAVA + DB = JDBC (0) | 2023.06.18 |
---|---|
[JAVA] 래퍼 클래스 (Wrapper Class)와 박싱(Boxing), 언박싱(UnBoxing) (0) | 2023.06.09 |
[JAVA] 제네릭 (Generic) (0) | 2023.06.07 |
[JAVA] 컬렉션 프레임워크 3 - Map (0) | 2023.06.05 |
[JAVA] 컬렉션 프레임워크 2 - Set (0) | 2023.06.05 |