티스토리 뷰

728x90
반응형

목표

자바의 멀티쓰레드 프로그래밍에 대해 학습하기

 

스터디 목차

  • Thread 클래스와 Runnable 인터페이스
  • 쓰레드의 상태
  • 쓰레드의 우선순위
  • Main 쓰레드
  • 동기화
  • 데드락

 

1. Thread 클래스와 Runnable 인터페이스

 

Thread란

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

 

멀티 태스킹과 멀티쓰레딩

멀티태스킹여러개의 프로세스를 동시에 실행하는 것이다. 그렇다면, 왜 굳이 멀티태스킹(멀티프로세스)로 처리하면 될 것을 다시 쓰레드까지 쪼개서 처리해야 될까?

 

문제는 바로 프로세스를 호출 시 발생하는 Context switch(문맥교환)에 있다. 프로세스는 호출할 때마다 문맥교환이라는 오버헤드가 발생하는데 스레드로 처리를 하면 프로세스 끼리 통신하는 비용보다 통신 비용이 적고, 문맥교환이 적게 발생하기 때문에 보다 효율적인 작업이 가능하다.

 

그러나 멀티쓰레드가 장점만 있는것이 아니다. 대부분의 문제는 멀티쓰레드 프로세스는 여러 쓰레드가 같은 프로세스 내에서 자원을 공유하면서 작업을 하기 때문에 동기화(Synchronization), 교착상태(Deadlock)와 같은 문제들이 발생할 수가 있다.

 

Thread 생성

  • Thread 클래스를 상속받는 방법
public class ThreadTest extends Thread{
	public void run(){
    	//수행할 문장
    }
}

public class Thread1{
	public static void main(String args[]){
    	ThreadTest t1 = new ThreadTest();
        t1.start()
    }
}

 

  • Runnable 인터페이스를 구현하는 방법
public class RunnableTest implements Runnable{
	public void run(){
    	// 수행할 문장
    }
}

public class Thread2{
	public static void main(String args[]){
    	Thread th1 = new Thread(new RunnableTest());
    	th1.start();
    }
}

 

2가지 방법으로 작성한 클래스의 쓰레드 실행 방법이 약간 다르다.

 

두 가지 클래스 모두 Thread클래스의 start() 메소드를 통해서 실행시킬수 있는데 Thread를 상속받은경우는 해당객체에 start() 메소드를 직접 호출할 수 있지만

Runable을 구현한 클래스의 경우에는 Runable형 인자를 받는 생성자를 통해 별도의 Thread 객체를 생성 후 start() 메소드를 호출해야 한다.

 

Thread vs Runnable

Thread 클래스를 확장하는 것이 실행 방법이 더 간단하지만 자바에서는 다중 상속을 허용하지 않기 때문에, Thread클래스를 확장하는 클래스는 다른 클래스를 상속받을수 없다.

 

Runnable 인터페이스를 구현했을 경우에는 다른 인터페이를 구현할 수 있을 뿐만 아니라, 다른 클래스도 상속받을 수 있기때문에 많은 개발자들이 대부분의 상황에서 Runnable 클래스를 구현하는 것을 선호한다.

 

start() 메서드와 run() 메서드의 차이

start() 메서드는 현재 스레드를 스레드풀에 등록하는 것이다. 스레드 풀에 등록된 스레드는 쉬고 있다가 스레드 스케줄러가 호출했을때 그 스레드의 run() 메서드가 실행되는 것이다.

 

그렇게 때문에 main() 메서드에서 start()를 실행하지 않고 run()메서드를 호출했다면 단순한 객체의 run() 메서드를 호출한 것으로 판단해 새로운 흐름이 생기지 않는다.

 

스레드풀 (ThreadPool)

병렬 작업 처리가 많아지면 스레드 수가 증가되고 그에 따른 스레드 생성과 스케줄링으로 인해 CPU가 바빠져서 메모리 사용량이 늘어난다. (애플리케이션 성능 저하) 따라서 스레드의 폭증을 막으려면 스레드풀을 사용해야 한다.

 

스레드 풀은 작업 처리에 사용되는 스레드를 제한된 개수만큼 정해 놓고 작업 큐에 들어오는 작업들을 하나씩 스레드가 맡아 처리한다.

 

java.util.concurrent 패키지를 사용하여 스레드 풀을 생성할 수 있다.

  • Executor 클래스
  • ExecutorService 인터페이스

 

 

 

2. 쓰레드의 상태

 

쓰레드 상태확인은 쓰레드 클래스에 있는 getState() 메소드를 사용하면 Thread.State 열거 상수를 리턴한다.

  • NEW : 스레드가 생성된 상태, 아직 start() 되지 않음
  • RUNNABLE : start()가 호출되어 실행 대기,
  • Running :  run()이 호출되어 cpu가 점유된다.
  • WAITING : 일시 정지, 다른 스레드의 통지를 기다림
  • TIMED_WAITING : 일시 정지, 주어진 시간동안 기다림
  • BLOCK : 일시 정지, 사용하려는 객체의 lock이 풀릴때 까지 대기
  • TERMINATED : 실행 마치고 종료, run()이 끝나면 TERMINATED 되면서 소멸

 

쓰레드 상태제어 메서드

 

 

 

3. 쓰레드의 우선순위

 

쓰레드 우선순위

쓰레드 스케줄링에 의해 쓰레드들이 짧은 시간에 번갈아가면서 run() 메소드를 조금씩 실행하는데 우선순위를 설정으로 높은 우선순위가 낮은 우선순위 스레드 보다 실행 상태를 더 많이 가지도록 스케줄링 하는 것을 말한다.

 

우선순위는 1부터 10까지 있으며 1이 가장 우선순위가 낮고 기본적으로 따로 설정이 없으면 5로 설정된다.

 

thread.setPriority(10);

 

 

 

4. Main 쓰레드

 

메인스레드는 main() 메소드를 실행하며 시작된다. 즉 메인스레드는 main메소드의 코드 흐름이다. 메인스레드가 없다면 멀티스레드가 나올 수 없다.

 

public static void main(String[] args) { // 메인 스레드 시작
	...
    	...
} // 메인스레드 끝

 

메인스레드 흐름안에서 싱글 스레드가 아닌 멀티 스레드 어플리케이션은 필요에 따라 작업 스레드를 만들어 병렬로 코드를 실행할 수 있다.

 

싱글 스레드 같은 경우 메인 스레드가 종료되면 프로세스도 종료되지만, 멀티 스레드는 메인 스레드가 종료되더라도 실행중인 스레드가 하나라도 있다면 프로세스는 종료되지 않는다.

 

메인스레드가 먼저 종료되지 않게 하려면 join 메서드를 이용하면 된다.

 

데몬 스레드

데몬 스레드는 메인 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드로 주 스레드가 종료되면 데몬 스레드는 더는 존재 의미가 없기에 강제로 종료가 된다.

 

데몬스레드를 만드는 방법은 스레드를 만들고 해당 스레드에setDaemon(true); 메소드를 세팅하면 된다.

 

public static void main(String args[]){
    Thread deamon = new Thread(()->{
        while ( true ) {
            System.out.println(" 데몬 스레드가 실행 중입니다.");
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
    
    deamon.setDaemon(true);
    deamon.start();
    
     try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

 

 

 

5. 동기화 (Synchronized)

 

싱글쓰레드 프로세스의 경우 프로세스 내에 단 하나의 쓰레드만 작업하기 때문에 프로세스의 자원을 가지고 작업하는 데 문제가 없지만, 멀티쓰레드 프로세스의 경우 여러 쓰레드가 같은 프로세스 내의 자원을 공유해서 작업을 하기 때문에 서로의 작업에 영향을 주게된다.

 

자바에서는 키워드 synchronized를 통해 공유데이터를 사용하는 코드 영역을 임계 영역으로 지정해놓고, 공유 데이터(객체)가 가지고있는 lock을 획득한 단 하나의 쓰레드만 이 영역 내의 코드를 수행할 수 있게 된다.

 

그리고 해당 쓰레드가 임계 영역 내의 모든 코드를 수행하고 벗어나서 lock을 반납해야만 다른 쓰레드가 반납된 lock을 획득하여 임계 영역의 코드를 수행할 수 있게 된다.

 

  • 특정 객체에 lock을 걸고자 할 때
synchronized(객체의 참조변수){
	...
}

 

  • 메서드에 lock을 걸고자 할 때
public synchronized void test1(){
	//
}

 

 

 

6. 데드락(Deadlock)

 

데드락 이란 교착상태를 말하고, 두 개 이상의 작업이 하나씩 자원을 소지하고 있으면서 상대방이 가진 자원을 서로 원하고 있는 상태를 말한다. 어떤 작업도 실행되지 못하고 계속 서로 상대방의 작업이 끝나기만 바라는 무한정 대기상태이다.

 

데드락 발생조건

 

교착상태는 한 시스템 내에서 다음의 네 가지 조건이 동시에 성립 할 때 발생한다.

따라서, 아래의 네가지 조건 중 하나라도 성립하지 않도록 만든다면 교착상태를 해결할 수 있다.

 

  • 상호 배제 (Mutual exclusion) - 자원은 한 번에 한 프로세스만이 사용할 수 있어야 한다.
  • 점유대기 (Hold and wait) - 최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.
  • 비선점 (No preemption) - 다른 프로세스에 할당된 자원은 사용이 끝날 때 까지 강제로 빼앗을 수 없어야한다.
  • 순환 대기 (Circular wait) - 프로세스의 집합 {P0, P1, ,…Pn}에서 P0 P1이 점유한 자원을 대기하고 P1 P2가 점유한 자원을 대기하고 P2…Pn-1 Pn이 점유한 자원을 대기하며 Pn P0가 점유한 자원을 요구해야 한다.

 

데드락 처리

  • 교착상태 예방 및 회피 - 교착 상태가 되지 않도록 보장하기 위하여 교착 상태를 예방하거나 회피하는 프로토콜을 이용하는 방법
  • 교착상태 탐지 및 회복 - 교착 상태가 되도록 허용한 다음에 회복시키는 방법
  • 교착 상태 무시 - 대부분의 시스템은 교착 상태가 잘 발생하지 않으며, 교착상태 예방, 회피, 탐지, 복구하는 것은 비용이 많이 든다.

 

 

 

 

 

Reference


www.daleseo.com/java-thread-runnable/

 

자바: Thread 클래스와 Runnable 인터페이스

Engineering Blog by Dale Seo

www.daleseo.com

devbox.tistory.com/entry/Java-%EC%93%B0%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EA%B8%B0%ED%99%94

 

[Java] 쓰레드의 동기화

쓰레드의 동기화 싱글쓰레드 프로세스의 경우 프로세스 내에 단 하나의 쓰레드만 작업하기 때문에 프로세스의 자원을 가지고 작업하는 데 별문제가 없지만, 멀티쓰레드 프로세스의 경우 여러

devbox.tistory.com

gosmcom.tistory.com/19

 

[JAVA] 멀티스레드_1.개념과 메인스레드

■1. 프로세스, 간단하게는 '작업'이며, 운영체제에서는 실행 중인 프로그램(어플리케이션)을 말한다. 하나의 프로그램이 다중 프로그램을 만들기도 한다. ■2 멀티 태스킹(Multi tasking)은 두 가지

gosmcom.tistory.com

honbabzone.com/java/java-thread/

 

JAVA 쓰레드란(Thread) ? - JAVA에서 멀티쓰레드 사용하기

JAVA에서 Thread사용하는 방법을 배우고 멀티코어 환경에서 멀티 쓰레드를 사용하는 방법을 알아보겠습니다.

honbabzone.com

includestdio.tistory.com/12

 

[운영체제] 데드락, 교착상태 해결 (Dead lock)

1. 데드락 (Dead lock) 이란? - ‘교착 상태’라고도 하며 한정된 자원을 여러 곳에서 사용하려고 할 때 발생할 수 있다. - 데드락이 발생할 수 있는 경우 - 멀티 프로그래밍 환경에서 한정된 자원을

includestdio.tistory.com

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30