본문 바로가기
개발/JAVA

[JAVA] Thread

by 경주초이 2020. 6. 25.

동작하고 있는 프로그램을 프로세스(Process)라고 한다. 보통 한 개의 프로세스는 한 가지의 일을 하지만, 이 쓰레드를 이용하면 한 프로세스 내에서는 두 가지 또는 그 이상의 일을 동시에 할 수 있게 된다.

 

Thread


Test.java

public class Test extends Thread {
    public void run() {
        System.out.println("thread run.");
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.start();
    }
}

위 예제를 실행하면 "thread run." 이라는 문장이 출력 될 것이다. 하지만 위 처럼 쓰레드가 하나인 경우에는 도대체 쓰레드가 어떻게 동작하고 있는지 알 수가 없다.

다음과 같이 Test 클래스를 수정해보자.

public class Test extends Thread {
    int seq;
    public Test(int seq) {
        this.seq = seq;
    }
    public void run() {
        System.out.println(this.seq+" thread start.");
        try {
            Thread.sleep(1000);
        }catch(Exception e) {

        }
        System.out.println(this.seq+" thread end.");
    }

    public static void main(String[] args) {
        for(int i=0; i<10; i++) {
            Thread t = new Test(i);
            t.start();
        }
        System.out.println("main end.");
    }
}
0 thread start.
2 thread start.
1 thread start.
3 thread start.
4 thread start.
6 thread start.
5 thread start.
7 thread start.
8 thread start.
main end.
9 thread start.
0 thread end.
1 thread end.
4 thread end.
2 thread end.
3 thread end.
7 thread end.
5 thread end.
6 thread end.
9 thread end.
8 thread end.

0번부터 9번 쓰레드까지 순서대로 실행되지 않고 실행 순서가 일정하지 않은걸 보면 쓰레드는 순서에 관계없이 동시에 실행된다는 사실을 알 수 있다.

 

Join


위 예제에선 쓰레드가 모두 시작되고 종료되기 전에 main 메소드가 먼저 종료되었다. 모든 쓰레드가 종료된 후 main메소드를 종료시키고 싶은 경우에는 어떻게 해야할까

public static void main(String[] args) {
    ArrayList<Thread> threads = new ArrayList<Thread>();
    for(int i=0; i<10; i++) {
        Thread t = new Test(i);
        t.start();
        threads.add(t);
    }

    for(int i=0; i<threads.size(); i++) {
        Thread t = threads.get(i);
        try {
            t.join();
        }catch(Exception e) {
        }
    }
    System.out.println("main end.");
}

생성되는 쓰레드를 담기 위해서 ArrayList 객체인 threads를 만든 후 쓰레드 생성시 생성된 객체를 threads에 저장한다. main 메소드가 종료되기 전에 threads 에 담긴 각각의 thread에 join 메소드를 호출하여 쓰레드가 종료될 때까지 대기하도록 변경하였다.

"main end." 라는 문자열이 가장 마지막에 출력되는 것을 확인 할 수 있다.

쓰레드 프로그래밍 시 가장 많이 실수하는 부분이 바로 쓰레드가 종료되지 않았는데 쓰레드가 종료된 줄 알고 그 다음 로직을 수행하게 만드는 일이다. 쓰레드가 종료된 후 그 다음 로직을 수행해야 할 때 꼭 필요한 것이 바로 이 join 메소드이다.

 

Runnable


import java.util.ArrayList;

public class Test implements Runnable {
    int seq;
    public Test(int seq) {
        this.seq = seq;
    }
    public void run() {
        System.out.println(this.seq+" thread start.");
        try {
            Thread.sleep(1000);
        }catch(Exception e) {
        }
        System.out.println(this.seq+" thread end.");
    }

    public static void main(String[] args) {
        ArrayList<Thread> threads = new ArrayList<Thread>();
        for(int i=0; i<10; i++) {
            Thread t = new Thread(new Test(i));
            t.start();
            threads.add(t);
        }

        for(int i=0; i<threads.size(); i++) {
            Thread t = threads.get(i);
            try {
                t.join();
            }catch(Exception e) {
            }
        }
        System.out.println("main end.");
    }
}

Thread를 extends 하던 것에서 Runnable을 implements 하도록 변경되었다. (Runnable 인터페이스는 run 메소드를 구현하도록 강제한다.) 그리고 Thread 를 생성하는 부분을 다음과 같이 변경했다.

Thread t = new Thread(new Test(i));

Thread의 생성자로 Runnable 인터페이스를 구현한 객체를 넘길 수 있는데 이 방법을 사용한 것이다. 이렇게 변경된 코드는 이 전에 만들었던 예제와 완전히 동일하게 동작한다. 다만 인터페이스를 이용했으니 상속 및 기타 등등에서 좀 더 유연한 프로그램으로 발전했다고 볼 수 있겠다.

 

 

 

'개발 > JAVA' 카테고리의 다른 글

[SpringBoot] Interceptor 설정  (0) 2020.08.13
[JAVA] 예외처리 Exception  (0) 2020.06.24
[JAVA] 다형성  (0) 2020.06.21
[JAVA] 인터페이스  (0) 2020.06.17
[JAVA] 생성자  (0) 2020.06.15