스터디/혼공학습단

[혼공학습단] 혼공자 9기 4주차

Jop 2023. 2. 4. 16:45
반응형

안녕하세요 벌써 1월이 다 지나갔네요

나이가 들수록 시간이 더 빨리지나가는 기분이예요 🥹

그래도 혼공학습단 덕분에 뿌듯하게 1월이 마무리 되는 기분이예요

다가오는 2월도 화이팅 해보겠습니다! 👍

 

 📄 혼공자 3주차 미션 (진도 Chapter 12)

기본미션 : p.550 [직접 해보는 손코딩] 코딩 과정 및 실행 결과 캡쳐하기

선택미션 : p.539 문제 2번 풀고, 풀이 과정 설명하기

 

 📄 기본미션 ( p.550 [직접 해보는 손코딩] 코딩 과정 및 실행 결과 캡쳐하기 )

1초 주기로 save() 메소드를 자동 호출하도록 AutoSaveThread를 작성하고, 메인 스레드가 3초후 종료되면 AutoSaveThread도 같이 종료되도록 AutoSaveThread를 데몬 스레드로 생성

 

📄 선택미션 ( p.539 문제 2번 풀고, 풀이 과정 설명하기 )

문제. 동영상과 음악을 재생하기 위해 두 가지 스레드를 실행하려고 합니다. 1 ~ 3 위치에 적당한 코드를 넣어보세요.

ThreadExample.java

public class ThreadExample {


    public static void main(String[] args){
        Thread thread1 = new MovieThread();
        thread1.start();

        MusicRunnable musicRunnable = new MusicRunnable();
        Thread thread = new Thread(musicRunnable);
        thread.start();
    }
}

MovieThread.java

public class MovieThread extends Thread {
    @Override
    public void run(){
        for(int i = 0; i<3; i++){
            System.out.println("동영상을 재생합니다.");
        }
        try{
            Thread.sleep( 1000 );
        } catch ( InterruptedException e ){

        }
    }
}

MusicRunnable.java

public class MusicRunnable implements Runnable{

    @Override
    public void run () {
        for(int i=0; i<3; i++){
            System.out.println("음악을 재생합니다.");
        }
        try{
            Thread.sleep( 1000 );
        }catch ( InterruptedException e ){

        }
    }
}

1 : new MusicRunnable();

Thread 클래스로부터 작업 스레드 객체를 직접 생성할려면 Runnable을 매개값으로 갖는 생성자를 호출해야합니다.

2 : extends Thread

작업 스레드 클래스를 정의 했을 경우, Thread 클래스를 상속한 후 run() 메소드를 재정의 해서 스레드가 실행할 코드를 작성해줘야 합니다.

3 : implements Runnable

MusicRunnable은 Thread 클래스로 부터 값는 매개값으로 Runnable 인터페이스를 상속받아 만들어진 Runnable 구현 클래스 입니다.

 

📄 내용정리

Chapter12 스레드

스레드(thread)는 한 가지 작업을 실행하기 위해 순차적으로 실행할 코드를 실처럼 이어놓았다는 말에서 유래된 이름

하나의 스레드는 하나의 코드 실행 흐름이기 때문에 한 프로세스 내에 스레드가 2개라면 2개의 코드 실행 흐름이 생긴다는 의미

 

메인 스레드

자바의 모든 애플리케이션은 메인 스레드(main thread)가 main() 메소드를 실행하면서 시작합니다. 메인스레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실행하고, main() 메소드의 마지막 코드를 실행하거나 return문을 만나면 실행이 종료됩니다.

 

싱글 스레드 애플리케이션에서는 메인 스레드가 종료하면 프로세스도 종료됩니다. 하지만 멀티 스레드 애플리케이션에서는 실행 중인 스레드가 하나라도 있다면, 프로세스는 종료되지 않습니다. 메인스레드가 작업 스레드보다 먼저 종료되더라도 작업 스레드가 계속 실행 중이라면 프로세스는 종료되지 않습니다.

 

어떤 자바 애플리케이션이건 메인 스레드는 반드시 존재하기 때문에 메인 작업 이외에 추가적인 병렬 작업의 수 만큼 스레드를 생성하면 됩니다. 자바에서는 작업 스레드도 객체로 생성되기 때문에 클래스가 필요합니다.

Thread클래스를 상속해서 하위 클래스를 만들어 생성하는 방법, Thread 클래스를 직접 객체화하는 방법

 

Thread클래스로 부터 직접 생성

Thread thread = new Thread(new Runnable() {
	public void run() {
    	//스레드가 실행할 코드;
    }
} // 익명구현 객체 Runnable()
);

Runnable은 작업 내용을 가지고 있는 객체이지 실제 스레드는 아닙니다. Runnable 구현 객체를 생성한 후, 이것을 매개값으로 해서 Thread를 호출해야 작업 스레드가 생성됩니다.

Runnable task = new Task();

Thread thread = new Thread(task);

 

동기화 메소드

싱글 스레드 프로그램에서는 1개의 스레드가 객체를 독차지 하지만 멀티 스레드 환경에서는 스레드 들이 객체를 공유해서 작업해야되는 경우가 있습니다.  스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없게 하려면 스레드 작업이 끝날 때까지 객체에 잠금을 걸어서 다른 스레드가 이용할 수 없도록 해야합니다.

단 하나의 스레만 실행할 수 있는 코드 영역을 임계 영역이라 부르는데 자바에서는 이 임계 영역을 지정하기 위해 동기화 메소드를 제공합니다.

 

동기화 메소드 선언 (synchronized 키워드 이용)

public synchronized void method() {
	//임계영역;
    //단 하나의 스레드만 실행
}

 

키워드 정리

프로세스 (process)

애플리케이션을 실행하면 운영체제로부터 실행에 필요한 메모리를 할당받아 애플리케이션이 실행되는데, 이것을 프로세스라고 합닏.

 

멀티 스레드 (multi thread)

하나의 프로세스 내에 동시 실행을 하는 스레드들이 2개 이상인 경우

 

메인 스레드 (main thread)

자바의 모든 애플리케이션은 메인 스레드가 main() 메소드를 실행하면서 시작합니다. 메인 스레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실행하고, main()메소드의 마지막 코드를 실행하거나 return문을 만나면 실행이 종료

 

작업 스레드

메인 작업 이외에 병렬 작업의 수만큼 생성하는 스레드

작업 스레드도 객체로 생성되기 때문에 클래스가 필요합니다.

Thread 클래스를 직접 객체와해서 생성, Thread 클래스를 상속해서 하위 클래스를 만들어 생성

 

동기화 메소드 

멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역

 

스레드 제어

스레드 객체를 생성하고 start() 메소드를 호출하면 바로 실행되는 것이 아니라 실행 대기 상태가 됩니다.

실행 상태의 스레드는 run() 메스드를 모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있으며, 실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 되기도 합니다.

 

스레드 상태 제어

실행 중인 스레드의 상태를 변경하는 것을 스레드 상태 제어

 

메소드 실행
interrupt() 일시 정지 상태의 스레드에서 InterruptedException을 발생시켜, 예외 처리 코드(catch)에서
실행 대기 상태로 가거나 종료 상태로 갈 수 있도록 합니다.
sleep(long millis) 주어진 시간 동안 스레드를 일시 정지 상태로 만듭니다. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 됩니다.
stop() 스레드를 즉시 종료합니다. 불안전한 종료를 유발하므로 사용하지 않는 것이 좋습니다.

 

스레드의 안전한 종료

1. stop 플래그를 이용하는 방법

public class XXXThread extends Thread {
	
    private boolean stop; // stop 플래그 필드
    
    public void run() {
    	while( !stop ){ // stop이 true가 되면 run()이 종료
        	스레드가 반복 실행하는 코드;
            
        }
        // 스레드가 사용한 자원 정리
   }
}

 

2. interrupt() 메소드 이용

interrupt()메소드는 스레드가 일시 정지 상태에 있을 때 InterruptedException을 발생시키는 역할을 합니다.

이를 이용하면 run()메소드를 정상 종료 할 수 있습니다.

public class InterruptExample {

    public static void main ( String[] args ) {
        PrintThread printThread = new PrintThread();
        printThread.start();

        try{
            Thread.sleep( 1000 );
        }catch ( InterruptedException e ){

        }
		
        // 스레드를 종료하기 위해 InterruptedException을 발생시킴
        printThread.interrupt();
    }

}

 

 

데몬 스레드

데몬 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다. 주 스레드가 종료되면 데몬 스레드는 강제적으로 종료되는데, 그 이유는 주 스레드의 보조 역할을 수행하므로 주 스레드가 종료되면 데몬 스레드의 존재 의미가 사라지기 때문입니다. 

 

데몬 스레드 생성

주 스레드가 데몬이 될 스레드의 setDaemon(true) 호출

public static void main(String[] args){

	AutoSaveThread thread = new AutoSaveThread();
   
    thread.setDaemon(true);
    thread.start();
    ...
}

 

키워드 정리

스레드 상태

스레드를 생성하고 시작하면 스레드는 다양한 상태를 가지게 됩니다. 스레드 상태는 자동으로 변경될 수도 있고, 코드에 의해서 변경될 수도 있습니다.

일시 정지

실쟁 중인 스레드를 일정 시간 멈추게 하고 싶다면 Thread 클래스의 정적 메소드인 sleep()을 사용하면 됩니다. 다음과 같이 Thread.sleep() 메소드를 호출한 스레드는 주어진 시간 동안 일시 정지 상태가 되고, 다시 실행 대기 상태로 돌아갑니다.

안전한 종료

Thread는 스레드를 즉시 종료하기 위해서 stop() 메소드를 제공하고 있는데, 이 메소드는 deprecated되었습니다. 그 이유는 stop()메소드로 스레드가 갑자기 종료하게 되면 스레드가 사용 중이던 자원들이 불안전한 상태로 남겨지기 때문입니다. 스레드를 안전하게 종료하기 위해서 stop 플래그를 이용하거나 interrupt()메소드를 이용하는 방법이 있습니다.

데몬 스레드

주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다. 주 스레드가 종료되면 데몬 스레드는 강제적으로 자동 종료되는데, 주 스레드의 보조 역할을 수행하므로 주 스레드가 종료되면 데몬 스레드의 존재 의미가 사라지기 때문입니다.

 

 

4주차 과제 마치도록 하겠습니다!

 

 

 

 

 

반응형