프로그램은 하드디스크에 저장되어 있고, 실행되어 프로그램이 활성화된 것을 프로세스라고 한다. 프로세스는 일련의 소스 코드, 데이터 및 계산 부분 그리고 CPU를 사용한다. 보통의 컴퓨터는 CPU가 하나이고 여러개의 프로세스가 동시에 실행된다. CPU 시간을 분할하여 여러 프로세스를 동작시킨다.
이러한 처리 방식을 멀티태스킹 또는 멀티프로그래밍이라고 한다.
스레드(Thread)는 프로세스에서 실행되는 일련의 소스 코드를 부르는 다른 말이다. 멀티스레드는 하나의 프로세스에 하나의 스레드가 아닌 여러 개의 스레드를 사용하는 것이다.
멀티스레드의 경우 하나의 프로세스에 있는 각 스레드는 서로 비동기적(asynchronous)으로 실행된다. 비동기적으로 실행된다는 것은 각 스레드의 실행에 있어 순서가 정해져있지 않다는 것이다.
하나의 스레드는 하나의 가상적인 CPU, 스레드의 코드, 스레드의 데이터로 구성되어 있다. 가상 CPU는 스레드 클래스에 의해 구성되고 코드는 스레드가 실행되는 내용, 데이터는 스레드의 코드가 사용하는 데이터이다.
스레드는 생성되어 start() 메서드 호출로 시작된다.
스레드 시작은 Runnable인 스레드를 실행시키는 것이고, 인터럽트나 sleepy(), yield()같은 조건에 따라 지연되거나 중단될 수 있다.
스레드 생성, 시작은 프로그래머에 의해 이루어지고, 실행 및 지연은 운영체제 스케쥴러의 안내 및 조정을 받아 실행된다.

스레드 각각은 우선순위를 가지고 비동기적 상태로 경쟁 (racing)에 의해 실행된다. 멀티스레드 프로그램의 경우 스레드들의 실행 순서 전체를 미리 지정하는 것은 불가능하고, 바람직하지도 않다. 단지 어느 정도의 실행 흐름만 제어 가능하다.
Java 스레드의 우선순위 값은 1~10까지 범위로 나뉘고 우선순위를 지정하지 않은 일반적인 스레드는 5의 값을 가지게 된다.
동일한 자원을 사용하는 경우 우선순위가 높은 순으로 실행되기 때문에 하나의 스레드의 실행이 끝난 뒤 다른 스레드가 실행이 된다. 이러한 상황은 이기적인 스레드(selfish thread)라고 한다.
멀티 스레드를 실행시키는 방법에는 sleep(long) 과 yield()가 있다.
각 스레드가 실행하는 동안에 일정한 시간만큼 sleep(long)을 하는 것이다. sleep(long)의 단위는 밀리세컨드(ms)로 해당 시간만큼 자신의 스레드가 실행하지 않는 것을 의미한다. 이때 같은 자원을 두고 경쟁하던 다른 스레드가 실행될 수 있다. sleep(long)으로 권한을 잠시 넘길 때는 자신보다 우선순위가 낮은 스레드도 실행 권한을 받을 수 있다.
yield()를 실행하면 같은 자원을 두고 경쟁하던 다른 스레드가 실행 될 수 있다. yield()로 권한을 넘길 때는 자신보다 우선 순위가 낮은 스레드는 권한을 받을 수 없고 우선 순위가 같은 스레드만 실행 될 수 있다.
스레드를 생성하는 방법에는 Thread 클래스를 상속받는 방법과 Runnable 인터페이스를 이용하는 방법이 있다.
Thread 클래스와 Runnable 인터페이스의 기능상 차이는 없으므로 어느것을 사용해도 된다. 이미 다른 클래스를 상속받은 상태일 때는 Runnable 인터페이스를 이용하고 그렇지 않은 경우에는 Thread 클래스를 상속받아 사용한다. 주 클래스의 멤버를 참조할 경우에는 Thread 클래스를 주 클래스의 inner 클래스로 작성하여 사용하는 것이 스레드를 관리하기 편하다.
public Thread()새로운 스레드 객체를 생성한다.
Thread(null, null, gname)를 호출한 것과 같다.
public Thread(Runnable target)target을 지정하여 스레드 객체를 생성한다.
Thread(null, target, gname)를 호출한 것과 같다.
target - run() 메서드가 호출되는 객체이다.
public Thread(ThreadGroup group, Runnabel target)스레드 그룹과, target을 지정하여 스레드 객체를 생성한다.
Thread(group, target, gname)를 호출한 것과 같다.
group - the thread group.
target - the object whose run method is called.
SecurityException 예외의 발생이 가능하다.
public Thread(String name)스레드 이름을 지정하여 스레드 객체를 생성한다.
Thread(null, null, name)를 호출한 것과 같다.
public Thread(ThreadGroup group, String name)스레드 그룹과 스레드 이름을 지정하여 스레드 객체를 생성한다.
Thread(group, null, name)를 호출한 것과 같다.
SecurityException 예외의 발생이 가능하다.
public Thread(Runnable target, String name)target과 스레드 이름을 지정하여 스레드 객체를 생성한다.
Thread(null, target, name)를 호출한 것과 같다.
public Thread(ThreadGroup group, Runnable target, String name)스레드 그룹과 target, 스레드 이름을 지정하여 스레드 객체를 생성한다.
SecurityException 예외의 발생이 가능하다.
TreadGroup group
해당 스레드를 하나의 그룹에 연결시킬 수 있음을 의미
Runnable target
스레드의 몸체가 되는 run() 메서드가 어느 클래스에 작성되는가의 문제
String name
스레드의 이름 지정
public class MyThread extends Thread {
public MyThread()
{
}
public void run()
{ //Thread 클래스의 run() 메서드 재정의
//원하는 스레드 동작이 있을 때 여기에 작성
while(true) {
System.out.println("Hello World");
}
}
}
//------------------------------------------------
MyThread mt = new MyThread();
Runnable 인터페이스를 이용하여 스레드를 생성하는 방법은 Runnable 인터페이스를 상속받아 생성한 Runnable 객체를 Thread의 클래스 값으로 사용하는 것이다.
public class MyThread implements Runnable {
public MyThread()
{
}
public void run()
{ //Runnable 인터페이스의 run() 메서드 재정의
//원하는 스레드 동작이 있을 때 여기에 작성
while(true) {
System.out.println("Hello World");
}
}
}
//------------------------------------------------
Runnable r = new MyThread();
Thread t = new Thread(t);
스레드를 시작하려면 생성된 스레드 객체를 start()하면 된다.
스레드의 실행이 끝나면 자동적으로 종료하게 되고 stop() 메서드에 의해서도 종료할 수 있다. 다만 stop()에 의해 종료된 스레드는 다시 start()에 의해 실행을 재개할 수 없다.
| Method | Return Type | Description |
|---|---|---|
| currentThread() | Thread | 현재 실행중인 스레드 리턴 |
| getName() | String | 스레드 이름 반환 |
| start() | void | 스레드 시작 |
| run() | void | 스레드의 내용 |
| sleep() | void | 시간지연 |
| isAlive() | boolean | 스레드 동작 확인 |
| activeCount() | int | 동작 중인 스레드 수 |
| interrupt() | voud | 스레드에 인터럽트 |
| yeild() | void | 스레드 실행 권한 양도 |
| join() | void | 스레드가 끝나거나, 지정한 시간이 지나기까지 대기 |
| suspend() / resume() | void | 스레드 동작 멈춤 / 재개 |
class MyThread extends Thread{
public MyThread(String name)
{
super(name);
}
public void run()
{
for(int i = 0; i < 5; i++) {
System.out.println("Thread name is " + getName());
try {
sleep(100);
} catch(InterruptedException e) {}
}
}
}
public class Test {
MyThread t1, t2, t3;
public void doRun() {
t1 = new MyThread("T1");
t2 = new MyThread("T2");
t3 = new MyThread("T3");
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join(100);
t3.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("All Threads are dead!");
}
public static void main(String[] args) {
Test test = new Test();
test.doRun();
}
}
Thread name is T3
Thread name is T1
Thread name is T2
Thread name is T2
Thread name is T1
Thread name is T3
Thread name is T1
Thread name is T2
Thread name is T3
Thread name is T1
Thread name is T3
Thread name is T2
Thread name is T1
Thread name is T2
Thread name is T3
All Threads are dead!
class MyThread implements Runnable{
public void run()
{
for(int i = 0; i < 5; i++) {
System.out.println("Thread name is " + Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch(InterruptedException e) {}
}
}
}
public class Test {
Runnable r1, r2, r3;
Thread t1, t2, t3;
public void doRun() {
r1 = new MyThread();
r2 = new MyThread();
r3 = new MyThread();
t1 = new Thread(r1, "T1");
t2 = new Thread(r2, "T2");
t3 = new Thread(r3, "T3");
t1.start();
t2.start();
t3.start();
try {
t1.join();
t2.join(100);
t3.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("All Threads are dead!");
}
public static void main(String[] args) {
Test test = new Test();
test.doRun();
}
}
Thread name is T1
Thread name is T2
Thread name is T3
Thread name is T2
Thread name is T1
Thread name is T3
Thread name is T1
Thread name is T2
Thread name is T3
Thread name is T1
Thread name is T2
Thread name is T3
Thread name is T1
Thread name is T3
Thread name is T2
All Threads are dead!
스레드들은 하나의 그룹으로 연결할 수 있는데 이를 스레드 그룹(ThreadGroup)이라고 한다.
스레드 그룹을 이용하면 여러 개의 스레드를 관리하고 제어하기가 용이하다.
public ThreadGroup(String name)public ThreadGroup(ThreadGroup parent, String name)
class MyThread extends Thread{
String name;
public MyThread(ThreadGroup tg, String name) {
super(tg, name);
this.name = name;
}
public void run() {
try {
sleep(100);
}catch(InterruptedException e) {
System.out.println("InterruptedException");
}
}
}
public class Test {
MyThread mt1, mt2, mt3;
ThreadGroup tg;
MyThread list[];
public Test() {
tg = new ThreadGroup("TG");
mt1 = new MyThread(tg, "one");
mt2 = new MyThread(tg, "two");
mt3 = new MyThread(tg, "three");
mt1.start();
mt2.start();
mt3.start();
}
public static void main(String[] args) {
Test test = new Test();
test.go();
}
public void go() {
System.out.println("getName() = " + tg.getName());
System.out.println("getMaxPriority() = " + tg.getMaxPriority());
System.out.println("activeCount() = " + tg.activeCount());
System.out.println("toString() = " + tg.toString());
int ac = tg.activeCount();
list = new MyThread[ac];
tg.enumerate(list, false);
for(int i = 0; i < list.length; i++) {
System.out.println("list[" +i +"].getName() = " + list[i].getName());
}
}
}
getName() = TG
getMaxPriority() = 10
activeCount() = 3
toString() = java.lang.ThreadGroup[name=TG,maxpri=10]
list[0].getName() = one
list[1].getName() = two
list[2].getName() = three