스터디할래 - 10주차 과제: 멀티쓰레드 프로그래밍

 https://github.com/whiteship/live-study

👍목표

 

자바의 인터페이스에 대해 학습하세요.

 

 

 

📖학습할 것 (필수)

 

📌 Thread 클래스와 Runnable 인터페이스

 


📌쓰레드의 상태

 

 

📌쓰레드의 우선순위

 

 

📌Main 쓰레드

 

 

📌동기화

 

 

📌데드락

 


 

Process

 

프로세스는 실행중인 프로그램으로 OS로부터 메모리를 할당 받는다. 

 

Thread

 

실제 프로그램이 수행되는 작업의 최소 단위로 하나의 프로세스는 하나 이상의 Thread를 가진다.

 

 

 

 

💡  Thread 클래스와 Runnable 인터페이스

 

자바에서 쓰레드를 생성하는 방법 중에는 Thread 클래스를 상속받는 것과 Runnable 인터페이스를 구현하는 방법이 존

 

재한다.

 

 

Thread 클래스 상속

class ThreadClass extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 15; i++) {
            System.out.print(hashCode() + "\n");
        }
        try {
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("main start");
        ThreadClass threadClass1 = new ThreadClass();
        ThreadClass threadClass2 = new ThreadClass();

        threadClass1.start();
        threadClass2.start();

        System.out.println("main end");
    }
}

output:
main start
main end
910374986
19789119
910374986
19789119
910374986
19789119
19789119
910374986
19789119
910374986
19789119
910374986
19789119
910374986
19789119
910374986
19789119
910374986
19789119
910374986

 

Thread 클래스를 상속받은 ThreadClass에서  hashcode를 15번 출력하고, sleep 5초간

 

실행하도록 run()을 재정의 하였다. Main 클래스에서 2개의 쓰레드를 생성하였는데 main의 시작과 끝을 출력하였고

 

2개의 쓰레드가 실행된다. 출력 결과를 보면 번갈아서 실행되는 것을 볼 수 있지만 코드를 테스트 하는 과정에서

 

thread1이 전부 실행된 후, thread2가 실행되기도 하였다.

 

 

 

 

 

Runnable 인터페이스 구현

import static java.lang.Thread.sleep;

class ThreadClass implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.print(hashCode() + "\n");
        }
        try {
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("main start");
        ThreadClass threadClass1 = new ThreadClass();
        ThreadClass threadClass2 = new ThreadClass();

        Thread thread1 = new Thread(threadClass1);
        Thread thread2 = new Thread(threadClass2);

        thread1.start();
        thread2.start();

        System.out.println("main end");
    }
}

Output:
main start
main end
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929
2044267887
588794929

 

 

Runnable 인터페이스를 구현한 클래스에서 run()을 재정의 하였다. 출력 예시와 동작은 Thread를 상속받은 클래스와 비

 

슷하게 동작하였다.

 


💡  쓰레드의 상태

 

쓰레드 객체를 생성하고 start()를 호출하면 바로 쓰레드가 실행되는 것처럼 보이지만, 실행 전 대기 상태가 된다. 실행 대

 

기 상태에 있는 쓰레드 중에서 쓰레드 스케줄링으로 선택된 쓰레드가 CPU를 점유하고 run()을 실행하며 이를 Running

 

상태라 한다. 쓰레드는 실행 상태와 대기 상태를 번갈아가면서 run() 메서드를 실행한다. 실행 상태에서 run()이 종료되면

 

더 이상 실행할 코드가 없기 때문에 쓰레드의 실행은 멈추고 종료 상태가 된다.

 

 

 

 

쓰레드는 실행 상태에서 대가 상태로 가지 않고 일시 정지 상태로 가기도 하는데 일시 정지 상태는 쓰레드가 실행할 수

 

없는 상태로 일시 정지 상태에는 WAITING, BLOCKED, TIMED_WAITING이 있으며 쓰레드가 다시 실행 상태로 가기 위해

 

서는 일시 정지 상태에서 실행 대기 상태로 가야 한다.

 

 

💡  쓰레드의 우선순위

 

자바의 쓰레드 스케줄링은 우선순위 방식과 Round-Robin 방식을 사용한다. 우선 순위 방식은 우선순위가 높은 스레드

 

가 실행 상태를 더 많이 가지도록 스케줄링을 하는 말하며 Round-robin 방식은 TimeSlice를 정해서 하나의 스레드를 정

 

해진 시간만큼 실행하고 다시 다른 쓰레드를 실행하는 방식을 말한다. 우선순위 방식은 쓰레드 객체에 우선 순위번호를

 

부여할 수 있기 때문에 개발자가 코드로 제어할 수 있다. 우선순위는 1부터 10까지 있으며, 1이 가장 낮고 10이 가장 높

 

으며 우선순위를 부여하지 않을 경우 모든 스레드는 기본적으로 5를 할당 받는다. 

 

 

class ThreadClass extends Thread {
    ThreadClass(String name) {
        setName(name); // 쓰레드 이름 변경
    }
    @Override
    public void run() {
        for (int i = 0; i < 1000000000; ++i) {}
        System.out.println(getName()); // 스레드의 이름 호출
    }
}

public class Main {
    public static void main(String[] args) {

        for (int i = 1; i <= 10; ++i) {
            Thread thread = new ThreadClass("Thread-" + i);
            if (i == 10) {
                thread.setPriority(Thread.MAX_PRIORITY);
            }
            /*
            if (i == 1) {
            	thread.setPriority(Thread.MIN_PRIORITY);
            }
            */
            thread.start();
        }
    }
}

Output:
Thread-10
Thread-3
Thread-9
Thread-1
Thread-5
Thread-2
Thread-4
Thread-6
Thread-7
Thread-8

스레드를 1부터 10까지 생성하고, 10억번의 반복문을 수행하고 쓰레드의 이름을 출력하는 동작을 하도록 하였으며, 쓰

 

레드10의 우선순위를 10으로 두었다. 10의 우선순위를 가장 높게 하였기 때문에 쓰레드10이 먼저 수행되었고 나머지 쓰

 

레드는 기본 우선순위인 5 상태에서 수행 되었다. 쓰레드 우선순위를 1로 두고 해보았지만 우선순위가 가장 낮은 숫자를

 

부여해도 가장 늦게 종료 되지는 않았다.

 

💡  Main 쓰레드

 

 

자바 애플리케이션은 메인 쓰레드가 main() 메서드를 실행하면서 시작된다. 메인 쓰레드는 main() 메서드의 코드를 순차

 

적으로 실행하며, 마지막 코드를 실행하거나 return 문을 만나면 실행이 종료 된다. 싱글 쓰레드 애플리케이션에서는 메

 

인 쓰레드가 종료되면 프로세스도 종료되지만, 멀티 쓰레드 애플리케이션에서는 실행 중인 쓰레드가 하나라도 존재하면,

 

프로세스는 종료 되지 않으며 메인 쓰레드가 다른 쓰레드보다 먼저 종료 되더라도 쓰레드가 계속 실행 중이라면 프로세

 

스는 종료 되지 않는다. 

Thread 클래스와 Runnable 인터페이스

의 예시 코드에서 메인 쓰레드는 "main end" 를 출력하고 종료 되었지만 다른 쓰레드의 sleep이 실행 중이 었기 때문에

 

프로세스가 종료되지 않은 것이 이와 같은 동작 때문이라 할 수 있다.

 

 

💡  동기화

 

쓰레드 프로그램에서 한 개의 쓰레드가 객체를 독차지해서 사용하면 되지만 멀티 쓰레드 프로그램에서는 쓰레드들이 객

 

체를 공유해서 작업해야 하는 경우가 있는데 쓰레드1을 사용하던 객체가 쓰레드2에 의해 상태가 변경될 수 있기 때문에

 

쓰레드1이 의도했던 것과 다른 결과가 산출될 수 있다. 자바에서는 쓰레드가 사용 중인 객체를 다른 쓰레드가 변경할 수

 

없도록 하기 위해 synchronized 메서드와 동기화 블록을 제공한다. 쓰레드가 객체 내부의 동기화 매서드 또는 블록에 들

 

어가면 즉시 객체에 잠금(Lock)을 걸어 다른 쓰레드가 실행하지 못하도록 한다. 동기화 메서드를 만드는 방법은 메서드

 

선언에 synchronized 키워드를 붙이면 된다.

 

public synchronized void method() {
	// critical section 임계 영역.
}

동기화 메서드는 메서드 전체가 임계 영역이므로 쓰레드가 동기화 메서드를 실행하는 즉시 객체는 lock이 걸리며 쓰레드

 

가 synchronized 메서드 실행을 종료하면 lock이 풀린다.

 

public void method() {
	//실행 가능한 코드가 위치
    synchronized(공유객체) {
        critical section 임계영역
    }
    //실행 가능한 코드가 위치
    
}

 

일부 내용만 lock을 걸고 싶으면, synchronized 블록을 만들어서 하나의 스레드만 실행 가능한 상태로 만들 수 있다.

 

 

 

💡  데드락

 

데드락은 둘 이상의 쓰레드가 lock을 기다리는데, 다른 쓰레드도 똑같이 해당 lock을 기다리고 있어 서로 block 상태에

 

놓이는 것을 말한다. 

 

 

이미지 출처: https://barunmo.blogspot.com/2013/06/deadlock.html

 

Dead락을 예방하기 위한 몇가지 방법이 존재하는데 다음과 같다.

 

1. Lock이 발생하는 순서를 정한다.

 

2. 오픈 호출

 

3. Lock의 시간 제한

 

 

데드락에 대해선 학습 시간이 부족하여 추후 내용 보충 하도록 할 예정입니다.

 

 

References

이것이 자바다(신용권 저)
parkcheolu.tistory.com/19(데드락)
icednut.space/2016/08/06/20160806-about_deadlock (데드락)
TCP School