본문 바로가기

Java/기본

[Java] 스레드(Thread) - 스레드 개념 및 생성하기

수정이력

2022.08.29. 어색한 표현 정리. 오타 수정


 

프로세스란

  • 프로세스는 실행중인 프로그램을 의미한다
  • 프로세스는 완전히 독립적인 수행단위이다

스레드란

  • 스레드는 프로그램 내에서 실행되는 프로그램 제어 흐름(실행단위)을 말한다
  • 한 프로그램에 여러개의 스레드가 존재할 수 있다. 스레드가 1개라면 단일스레드, 2개이상이라면 다중스레드
  • 프로그램 코드를 한 줄씩 실행하는 것이 스레드의 역할이다 (=실행제어)
  • 스레드란 곧 프로그램을 실행하는 주체이다
  • 스레드를 보통 가벼운 프로세스(light-process)라고 표현한다

멀티스레드란

  • 멀티스레드 =multi thread =다중스레드
  • 멀티스레드는 여러개의 스레드를 이용하는 프로그램이다
  • 다중 스레드에서 각각의 스레드는 하나의 독립적인 프로세스처럼 작업 수행

 

작업관리자 > 성능 탭을 열어보면 프로세스와 스레드를 확인할 수 있다

 

멀티 스레드로 구현된 프로그램을 실행하면

  • 하나의 프로세서는 한번에 스레드1개밖에 실행시키지 못한다
  • 대신 일정한 시간 간격으로 수행해야하는 스레드를 전환한다
  • 스레드를 전환할 때는 운영체제의 스케줄러의 기준에 따라 순서가 정해지게 된다
  • 여러 스레드를 번갈아 처리하기 때문에 엄밀히 말하면 한번에 한가지를 처리하지만 동시에 작업하는 듯한 효과를 준다
  • 이와 같은 방식을 시분할 방식 이라고 한다

 

멀티 스레드 방식을 사용하는 이유(feat. 멀티스레드의 장점)

  • 프로세스는 독립적이다. 이 때문에 작업공간이 독립적이고, 프로세스끼리 자원 및 데이터를 공유하기 어렵다. 혹시 프로세스간 데이터전송이 필요한 경우 시간, 자원 소요가 많다.
  • 프로그램 내의 스레드는 서로 독립적이지 않다. 작업공간을 같이 사용하기 때문에 자원 및 데이터를 공유할 수 있다. 즉 스레드간 데이터전송이 필요한 경우 시간, 자원 소요가 적다.
  • 정리하자면 스레드는 프로세스처럼 작업을 동시에 처리할 수 있는 공통적인 특징이 있으면서, 프로세스보다 오버헤드가 적다는 것이 장점이다.

 

멀티 프로세싱 vs 멀티 태스킹 vs 멀티 스레드

용어
멀티프로세싱
(=multi processing)
멀티태스킹
(=multi tasking)
멀티 스레딩
(=multi threading)
관점 시스템 관점 프로그램 외부에서의 관점 프로그램 내부에서의 관점
의미 CPU 여러개에서
동시에 여러개의 프로세스 수행
CPU 1개에서 동시에
여러 프로그램을 실행
processor 1개가 동시에
여러 스레드를 실행
예시 다수의 송금거래를 동시에
처리하는 은행전산 시스템
pc카톡 켜놓고
youtube 음악들으면서
온라인뱅킹 업무
프로그램 안에서 실행되는
코드흐름이 여러개

 

멀티스레드 적용하기 위한 조건

  • 병행성(concurrency) : 다수의 스레드 생성방법 존재
  • 동기화(synchronization) : 작업이 방해받지 않고 각 스레드의 동기화 방법 존재
  • 통신(communication) : 서로 다른 스레드가 정보를 교환할 수 있는 방법이 존재

 


스레드 생성하기

스레드를 생성하는 방법은 2가지다.

  • Thread 클래스 상속받아서 생성
  • Runnable 인터페이스 구현하여 생성
Thread
클래스 상속
스레드 생성 -java.lang.Thread 클래스를 상속(extends)받아서 run() 메서드 오버라이딩
특징 -실행 스레드로 자신의 콜 스택을 갖춘 독립적인 프로세스
-start() 메서드를 통해 스레드가 시작된다
Runnable
인터페이스 구현
스레드 생성 -java.lang.Runnable 인터페이스로부터 run()메서드를 구현하여 생성한다
(참고로 Runnable 인터페이스는 run() 메서드 1개만 가지는 함수형 인터페이스이다)
특징 -Runnable 인터페이스를 구현한다고 해서 바로 스레드가 되지 않는다
Thread class 를 통해 스레드가 될 수 있다.
(방법 : 객체 참조변수를 인자값으로 하는 Thread 생성)

방법이 2가지인 이유는 자바가 단일상속만 허용하기 때문이다. 만약 상속받아야 하는 클래스가 있다면 Thread 클래스를 상속받는 방법 대신 Runnable 인터페이스를 구현하는 방법을 사용할 수 있다.

 

 

스레드 생성하기

생성자 내용
Thread() 일반적인 스레드 객체 생성
Thread-n 이런 이름을 가진 스레드가 만들어진다
Thread(Runnable target) run 메서드를 가지는 객체를 인자값으로 할당하기
Thread(Runnable target, String name) run 메서드를 가지는 객체와 스레드 이름을 인자값으로 할당하기
Thread(String name) 스레드 생성하면서 스레드 이름 지어주기

 

  • Thread 클래스 상속받아 thread 생성하기
public class Test01 extends Thread{
    @Override
    public void run() {
		/* 스레드 실행코드 */
    }
}

 

  • Runnable 인터페이스 구현하여 thread 생성하기
public class Test01 implements Runnable {
    @Override
    public void run() {
		/* 스레드 실행코드 */
    }
}

 

  • 스레드 5개 생성하는 멀티스레드 예제

Thread 상속받아 1개 생성

public class FirstThread extends Thread{
    @Override
    public void run() {
        System.out.println("1");
    }
}

Runnable 구현하여 1개 생성

public class SecondThread implements Runnable{
    @Override
    public void run() {
        System.out.println("2");
    }
}

 

외부 클래스로 스레드2개, 내부 클래스로 스레드 2개, 익명구현 객체로 1개생성

-> 총 5개의 스레드를 실행하는 코드

public class Test {
	//내부 클래스 - Thread 상속받기
    class ThirdThread extends Thread{
        @Override
        public void run() {
            System.out.println("3");
        }
    }

	//내부 클래스 - Runnable 구현
    class fourthThread implements Runnable{
        @Override
        public void run() {
            System.out.println("4");
        }
    }

//메인함수
    public static void main(String[] args) {
        Test t = new Test();        
        
        //스레드1
        FirstThread th1 = new FirstThread();
        th1.start();

        //스레드2
        SecondThread sec_thread = new SecondThread();
        Thread th2 = new Thread(sec_thread);
        th2.start();

        //스레드3
        ThirdThread th3 = t.new ThirdThread();
        th3.start();

        //스레드4
        Thread th4 = new Thread(t.new fourthThread());
        th4.start();
//        new Thread(t.new fourthThread()).start();

        /*
        스레드5 - 익명 객체구현객체 방식으로 생성
        	Thread 생성시 인자값으로 Runnable을 구현하는 코드 삽입하기
        */
        Thread th5 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("5");
                    }
                }
        );
        th5.start();
    }
}


실행결과

위 코드 실행결과는 알 수 없다. 실행할 때마다 결과가 다르기 때문이다. 아마 대부분 1 2 3 4 5 가 나오겠지만 1 3 4 2 5 가 나올 수도 있고 그외의 결과가 나오기도 한다. 이는 스레드를 실행하는데 우선순위가 정해져 있지 않기 때문이다.