[Java] 자바 - Thread란? 스레드 개념 및 사용방법
자바 - Thread란? 스레드 개념 및 사용방법
자바에서 여러가지 일을 동시에 처리하기 위해 사용되는 스레드(Thread)에 대해서 알아보도록 하겠습니다.
목차
- 프로세스와 스레드 (Process vs Thread)
- 스레드의 생성자와 메소드
- 스레드 생성방법
- Thread 클래스 상속 방식
- Runnable 인터페이스 구현 방식
- 스레드 사용예제
1. 프로세스와 스레드 (Process vs Thread)
1) 프로세스란?
프로세스(Process)는 일반적으로 cpu에 의해 메모리에 올려져 실행중인 프로그램을 말하며, 자신만의 메모리 공간을 포함한 독립적인 실행 환경을 가지고 있습니다. 우리가 사용하는 프로그램 중 일부는 여러 프로세스간 상호작용을 하는 것일수도 있습니다.
자바 JVM(Java Virtual Machine)은 주로 하나의 프로세스로 실행되며, 동시에 여러 작업을 수행하기 위해서 멀티 스레드를 지원하고 있습니다.
2) 스레드란?
스레드(Thread)는 프로세스안에서 실질적으로 작업을 실행하는 단위를 말하며, 자바에서는 JVM(Java Virtual Machine)에 의해 관리됩니다. 프로세스에는 적어도 한개 이상의 스레드가 있으며, Main 스레드 하나로 시작하여 스레드를 추가 생성하게 되면 멀티 스레드 환경이 됩니다. 이러한 스레드들은 프로세스의 리소스를 공유하기 때문에 효율적이긴 하지만 잠재적인 문제점에 노출될 수도 있습니다.
2. 스레드의 생성자와 메소드
1) 생성자
- Thread( ) : 새로운 스레드 객체 할당
- Thread(String name) : 새로운 스레드 객체가 할당되며, 스레드 이름은 name으로 설정됨
- Thread(Runnable target) : Runnable target이 구현된 스레드 객체 할당
- Thread(Runnable target, String name) : Runnable target이 구현된 스레드 객체가 할당되면 스레드 이름은 name으로 설정됨.
2) 메소드
- void run( ) : 스레드의 실행코드가 작성되는 메소드로 사용자는 run() 메소드를 오버라이드 하여 사용해야 합니다.
- void start( ) : 스레드가 시작되도록 요청하는 메소드로 JVM은 해당 스레드의 run() 메소드를 호출합니다.
- void interrupt( ) : 스레드를 중지 시킵니다.
- void join( ) : 이 스레드가 끝날때까지 기다립니다.
- void join(long millis) : 최대 millis 시간동안 이 스레드가 끝날때까지 기다립니다.
- static void sleep(long millis) : millis 시간동안 현재 스레드를 일시중지시킵니다.
- static void yield( ) : 현재 스레드의 실행시간을 다른 스레드에게 양보합니다.
- static Thread currentThread( ) : 현재 실행중인 스레드 객체의 참조값을 반환합니다.
- long getId( ) : 스레드의 Id를 반환합니다.
- String getName( ) : 스레드의 이름을 반환합니다.
- int getPriority( ) : 스레드의 우선순위 값을 반환합니다. (우선순위 범위 : 1 ~ 10)
- Thread.State getState( ) : 스레드의 state 값을 반환합니다.
- ThreadGroup getThreadGroup( ) : 스레드가 속한 스레드 그룹을 반환합니다.
- static boolean interrupted( ) : 현재 스레드의 interrupted 여부를 반환합니다.
- boolean isInterrupted( ) : 이 스레드의 interrupted 여부를 반환합니다.
- boolean isAlive( ) : 이 스레드가 살아있는지 여부를 반환합니다.
- boolean isDaemon( ) : 이 스레드가 데몬 스레드인지 여부를 반환합니다.
- void setDaemon(boolean on) : 이 스레드를 데몬 스레드로 변경합니다.
- void setName(String name) : 이 스레드의 이름을 name으로 변경합니다.
- void setPriority(int newPriority) : 이 스레드의 우선순위를 newPriority로 변경합니다.
- String toString( ) : 이 스레드의 이름, 우선순위, 스레드그룹등의 정보를 담은 문자열을 반환합니다.
cf) static 메소드는 해당 메소드를 호출한 스레드 자신에게 적용된다는 점에 유의해야합니다.
3. 스레드 생성방법
자바에서 스레드를 만드는 방법은 2가지가 있습니다. 하나는 Thread 클래스를 상속받는 방법과 다른 하나는 Runnable 인터페이스를 구현하는 방법입니다. 자바는 다중 상속을 허용하지 않기 때문에 Thread 클래스를 상속받게 되면 다른 클래스를 상속받을수가 없습니다. 대신 인터페이스인 Runnable을 이용하여 작성하게 되면 이러한 문제점을 해결하실 수 있습니다.
스레드를 생성하고 동작시킴에 있어서 알아두어야 할 점은 사용자가 스레드 객체를 생성하고 실행요청을 하더라도 스레드가 실행되는 것은 전적으로 JVM에 의한 스케쥴러에 따른다는 것입니다. 사용자는 다만 Thread의 여러 메소드들을 통해서 JVM에 해당 명령들이 실행되도록 요청하는 것입니다.
1) Thread 클래스 상속 방식
- Thread 클래스를 상속한 클래스 정의
- run() 메소드를 오버라이드하여 스레드 코드 작성
- 스레드 객체 생성하기
- start() 메소드로 스레드 시작하기
public class HelloWorld {
public static void main(String[] args) {
MyThread mt1 = new MyThread(); // 3.스레드 객체 생성
mt1.start(); // 4.스레드 실행
}
}
class MyThread extends Thread { // 1.Thread 클래스 상속한 클래스 정의
public void run() { // 2.run()메소드 오버라이드 및 스레드 코드 작성
System.out.println(this.getName());
}
}
2) Runnable 인터페이스 구현 방식
- Runnable 인터페이스를 구현하는 클래스 정의
- run() 메소드를 오버라이드하여 스레드 코드 작성
- Runnable 객체 생성하기
- Thread 객체 생성하기
- start() 메소드로 스레드 시작하기
public class HelloWorld {
public static void main(String[] args) {
Runnable r1 = new MyThread(); // 3.Runnable 객체 생성
Thread t1 = new Thread(r1); // 4.Thread 객체 생성
t1.start(); // 5.스레드 실행
}
}
class MyThread implements Runnable { // 1.Runnable 인터페이스를 구현하는 클래스 정의
public void run() { // 2.run()메소드 오버라이드 및 스레드 코드 작성
System.out.println(Thread.currentThread().getName());
}
}
4. 스레드 사용예제
1) 스레드 클래스 정의
public class MyThread extends Thread {
public MyThread(String string) {
super(string);
}
public void run() {
int count = 0;
while (!this.isInterrupted()) {
System.out.print(this.getName());
HelloWorld.threadSleep(this, 500);
count++;
if (count == 20) {
this.interrupt();
System.out.printf("%n[5]." + this.toString() + "-인터럽트됨]");
}
}
}
}
2) 스레드 객체 생성 및 실행
public class HelloWorld {
public static void main(String[] args) {
MyThread mt1 = new MyThread("*");
MyThread mt2 = new MyThread("#");
mt1.start();
mt2.start();
System.out.printf("%n[1].mt1:" + mt1.isInterrupted() + ", mt2:" + mt2.isInterrupted() + "]");
threadSleep(Thread.currentThread(), 2000);
mt1.interrupt();
System.out.printf("%n[2].mt1:" + mt1.isInterrupted() + ", mt2:" + mt2.isInterrupted() + "]");
threadJoin(mt2);
System.out.printf("%n[3].mt1:" + mt1.isInterrupted() + ", mt2:" + mt2.isInterrupted() + "]");
}
static void threadSleep(Thread t, long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
System.out.printf("%n[4]." + t.toString() + "-인터럽트됨]");
t.interrupt();
}
}
static void threadJoin(Thread t) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3) 실행결과
[1].mt1:false, mt2:false]#**#*##*
[2].mt1:true, mt2:false]
[4].Thread[*,5,main]-인터럽트됨]################
[5].Thread[#,5,main]-인터럽트됨]
[3].mt1:true, mt2:true]