Thread

2023. 11. 24. 18:58Java

1. Thread란? 
Thread는 프로세스와 마찬가지로 명령어가 프로세서를 이용하여 실행되어지는 객체의 기본단위이면서 명령어를 독립적으로 실행할 수 있는 하나의 제어 흐름이다.

2. Thread의 특징?
Thread는 같은 프로세스 안에서 동작하기 때문에 같은 주소 공간에 존재하게 되며 공유된 메모리를 같이 접근할수 있다.

3. Thread의 장점 
1) 어플리케이션의 성능 향상
코드와 데이터를 공유하면서 서로 다른 스레드의 활동을 허용하여 성능을 향상시키고 다중 스레딩은 일부가 차단 되거나 긴 작업을 수행하는 경우에도 실행하는 프로그램을 계속 허용 할 수 있다.

2) 문맥교환 비용 감소로 경제적인 효과
프로세스를 만들기 위한 메모리와 자원할당의 비용은 증가한다. 스레드는 프로세스 자원을 공유할수 있기 때문에 문맥교환이나 스레드 생성이 더 경제적이다. (단, 공유한 데이터를 접근하기 때문에 동기화 문제는 발생할 수 있다.) 

3) 다중 프로세서 구조 이용
다중 스레딩은 스레드가 여러 프로세서에서 병렬로 실행할 수 있는 환경을 제공한다.

그럼 이제 Java에서 Thread를 어떻게 사용하는지 알아볼까? 

지금까지 Thread에 대해서 아주 기본만 알아보았다. 그런데 왜 Thread를 만들었을까? 그 이유는 Process를 하나 만드려면 많은 자원이 필요하고 프로세스는 메모리 공간을 할당해야해서 만약 여러 개의 프로세스가 필요하다면 많은 자원을 사용하게 될 것이다.  이 때 필요한 것이 Thread이다. 프로세스는 1개 생성할때 32~64MB의 메모리 공간이 필요하지만 쓰레드 1개는 1MB 이내의 메모리가 필요하다. 그래서 경량 프로세스라고도 부른다. 

Java에서는 Thread를 만드는 방법이 2가지가 있다. 
1) Runnable interface를 사용하는 방법
2) Thread class를 이용하는 방법

먼저 Runnable interface를 사용하는 방법을 알아보자!

먼저 Runnable interface java doc문서를 보았다. 아래와 같은데 run method만 구현하면 된다.

Runnable run method

https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html

 

Runnable (Java Platform SE 8 )

The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run. This interface is designed to provide a common protocol for objects that wish to e

docs.oracle.com

먼저 아래와 같이 Runnable interface를 RunnableSample class에 구현한다.

public class RunnableSample implements Runnable {
    @Override
    public void run() {
        System.out.println("This is RunnableSample's run method!!");
    }
}

이렇게 하면 쓰레드를 실행할 수 있는 클래스가 만들어졌다. 아주 간단하다. 하지만 이것만 가지고는 실행할수가 없다. 
실행을 하려면 아래와 같이 쓰레드를 시작해주어야한다. 

public class Main {
    public static void main(String[] args) {
        Thread runnableThread = new Thread(new RunnableSample());
        runnableThread.start();
    }
}

한번 실행을 해보았다. 그랬더니 쓰레드가 잘 작동 되었다. Main class Program중에 runnableThread가 실행되었다.

그런데 여기서 의문점이 생긴게 있다. 

왜 run method로 실행하지 않고 start method로 했는데 RunnableSample의 run method가 실행이 될까?

그 해답은 start method 안에 들어가보면 답이 있다. 

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

들어가보면 아래와 같이 start0() method가 있는데 이 method는 아래와 같이 native method로 작성되었다. 아마도 C++로 작성되었나보다. 

private native void start0();

 그래서 공식 문서를 다시 찾아보았다.

 

public void start()
Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

 저 위를 보면 결국 JVM이 쓰레드의 run method를 부른다고 쓰여있다. 그래서 결국 쓰레드의 run method가 실행이 된다..

https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#start--

 

Thread (Java Platform SE 8 )

Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group, and has the specified stack size. This constructor is identical to Thread(ThreadGroup,Runnable,

docs.oracle.com

2) Thread class를 이용하는 방법

두번째 방법도 알아보자! 두번째 방법이 사실 더 쉬운거 같다. 아래처럼 처음부터 Thread class를 상속받는다. 그리고서 run method를 Override 해준다. 

public class ThreadSample extends Thread {
	@Override
    public void run() {
        System.out.println("This is ThreadSample's run() method!!");
    }
}

그리고서 main method에 아래와 같이 쓰레드를 실행한다.

public class Main {
    public static void main(String[] args) {
        ThreadSample threadSample = new ThreadSample();
        threadSample.start();
    }
}

그러면 위와 같이 쓰레드가 실행된다! 

지금까지 쓰레드의 기본 개념과 쓰레드를 자바에서 어떻게 생성하는지에 대해서 알아보았다! 좀 더 자세한 쓰레드 내용은 다른 글에서 작성할 예정이다.