sussa
컴퓨터가 할 일은 컴퓨터가.
sussa
전체 방문자
오늘
어제

블로그 메뉴

    • 분류 전체보기 (58)
      • Language (58)
        • JAVA (58)

    공지사항

    인기 글

    태그

    • recursion
    • 상속
    • 캡슐화
    • tree
    • java
    • 조건문
    • Database
    • binaryTree
    • Web
    • spring
    • 자료구조
    • CSS
    • 스파르타코딩클럽
    • Method
    • inheritance
    • BinarySearchTree
    • HTML
    • Algorithm
    • Til
    • DI
    • Stream
    • Class
    • singleton
    • 개발자
    • 최종연산
    • 다형성
    • Thread
    • 웹개발종합반
    • 재귀
    • Instance

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    sussa

    컴퓨터가 할 일은 컴퓨터가.

    Java Thread_02
    Language/JAVA

    Java Thread_02

    2022. 9. 5. 01:34

    🎯 목표 : 쓰레드의 활용 이해

    📒 Thread

     

    📌 Thread의 우선순위

    • 작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할수있다.
    • 우선순위를 정의하게 되면, 쓰레드를 생성한 쓰레드로 부터 상속받는다. main 메소드를 동작하게 하는 쓰레드는 기본 우선순위가 5이며, main 메소드 내에서 생성한 쓰레드는 모두 기본값 5를 가지고 동작한다.
    • 정의한 우선순위보다 OS 스케쥴러의 우선순위가 더 우선되기 때문에 정확하지 않다.

    📌 Thread 그룹

    • 서로 관련된 쓰레드를 그룹으로 묶어서 다룬다
    • 모든 쓰레드는 반드시 하나의 쓰레드 그룹에 포함되어 있다.
    • 쓰레드 그룹을 지정하지 않으면 main 쓰레드 그룹에 속하게 된다.
    • 자신이 생성한 쓰레드(부모 쓰레드)의 그룹과 우선순위를 상속받는다.
    • 쓰레드 그룹과 관련된 메소드를 가지고 다룰수 있다.

    📌 데몬 쓰레드(Daemon Thread)

    • 쓰레드는 일반 쓰레드와 데몬 쓰레드로 나뉜다.
    • 일반 쓰레드의 작업을 돕는 보조적인 역할을 하는게 데몬 쓰레드다.
    • 예를들면 Garbage Colletor, 자동 저장, 화면 자동갱신 등이 있다.
    • 무한 루프 반복문과 조건문으로 실행후 대기하다가 특정 조건에 부합하면 작업을 수행하고 다시 반복하며 대기하도록 작성한다.
    • setDaemon(true)를 호출하여 데몬 쓰레드를 실행하는데, 반드시 일반쓰레드를 실행하기 전에 호출해야한다.

    👉 예제

    public class DaemonThreadStudy implements Runnable  {
        static boolean autoSave = false;
    
        public static void main(String[] args) {
            Thread t = new Thread(new DaemonThreadStudy()); // 쓰레드 생성
            t.setDaemon(true);  //setDaemon 은 쓰레드 실행 전에 호출해야된다.
            t.start(); // 데몬 쓰레드 동작 시작
    
            for(int i=1; i <= 10; i++) { // 1초에 하나씩 증가하도록 설정
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException e) {}
                System.out.println(i);
    
                if(i==5) autoSave = true;// i 의 값이 5가 될때 true가 되며 데몬 쓰레드가 동작한다.
            }
    
            System.out.println("종료");
        }
    
        public void run() {
            while(true) {
                try {
                    Thread.sleep(3 * 1000); // 위 i 의 값이 5이후에는 3초마다 동작한다
                } catch(InterruptedException e) {}
    
                // autoSave의 값이 true 일때 autoSave()메소드를 호출한다.
                if(autoSave) autoSave();
            }
        }
    
        public void autoSave() {
            System.out.println("자동 저장됨...");
        }
    }
    • 위 예제에서 만약 쓰레드 t를 setDaemon호출하여 데몬 쓰레드로 만들지 않았다면, 이 예제의 run메소드 부분의 무한 반복문이 멈추지 않고 계속 돌게 될것이다. 데몬 쓰레드는 일반 쓰레드가 동작이 모두 끝나게 되면 함께 종료된다는 것을 확인할수 있다.

    📌 Thread의 상태와 실행제어

    출처 자바의 정석

    • 위 그림으로 쓰레드 들이 생성되고 실행되거나, 대기 상태가 되는 쓰레드 들의 상태 변화를 알수 있다.
    • start 메소드는 쓰레드를 실행 시키는 메소드가 아닌 실행 대기 상태로 만들어주는 메소드다.
    • 쓰레드의 실행과 대기를 제어할수 있는 메소드가 있으며 이를 활용해 효율적인 프로그램을 작성 할수있다.
    • static 메소드는 쓰레드 자기 자신에게만 호출 가능하다.

    출처 자바의 정석

    👉 sleep()

    • 지정 시간동안 쓰레드를 멈추게한다.
    • sleep에 의해 일시 정지된 쓰레드는 시간이 다 되거나, interrupt가 호출되면 InterruptedException이 발생하며 깨어나서 실행대기 상태가 된다 위 데몬 쓰레드 예제에서 확인할수 있다. 
    • 예외 처리를 해줘야한다. 아래와 같이 메소드를 만들어 활용할수도 있다.
    void sleepTh(long millis) {
    	try {
        	Thread.sleep(millis);
        } catch(InterruptedException e) {}
    }

    👉 interrupt() , interrupted()

    • 쓰레드의 작업을 취소한다.
    • 대기상태인 쓰레드를 실행 대기 상태로 만든다.
    void interrupt()            // 쓰레드의 interrupted 상태를 false에서 true로 변경
    boolean isInterrupted()     // 쓰레드의 interrupted 상태를 반환.
    static boolean interrupted()// 현재 쓰레드의 interrupted 상태를 반환 후 false로 변경

    2022.09.04 - [Language/JAVA] - Java Thread_01 의 멀티 쓰레드 예제를 수정하여 interrupt를 학습했다.

     

    Java Thread_01

    🎯 목표 : 프로세스와 쓰레드의 개념을 이해하고 Java에서 쓰레드의 활용을 이해 📒 Process, Thread 📌 프로세스는 공장 쓰레드는 일꾼 프로세스는 실행중인 프로그램 자원과 쓰레드로 구성되어있

    sussa1933.tistory.com

    import javax.swing.*;
    
    
    public class ThreadStudy3 {
        public static void main(String[] args) throws Exception {
            Thread1 th1 = new Thread1();
            th1.start();
    
            String input = JOptionPane.showInputDialog("입력하세요");
            System.out.println("입력값 : " + input );
            th1.interrupt();
            System.out.println("isInterrupted의 값 = "+th1.isInterrupted());
        }
    }
    class Thread1 extends Thread {
        public void run() {
            int i=10;
            while (i!=0&&!isInterrupted()){
                System.out.println(i--);
                for(long x=0; x<2500000000L; x++);
            }
            System.out.println("종료");
    
        }
    }
    • 쓰레드가 실행되고 input값을 입력하지 않으면 run() 메소드의 while 문은 계속 흘러간다.
    • input값을 입력하고 interrupt()가 호출되면, isInterrupted()의 값은 true가 되고, run()의 while문도 종료된다.
    ====출력값====
    10
    9
    8
    7
    6
    5
    입력값 : 1234
    isInterrupted의 값 = true
    종료

     

    👉 yield()

    • 남은시간을 다음 쓰레드에게 양보하고 자기 쓰레드(static)는 실행 대기.
    while (true){
    	if(!isInterrupted()){
        System.out.println(t--);
        try{
            Thread.sleep(10000);
        } catch(InterruptedException e) { 
        	interrupt();
            break;
            }
       }	
    }
    • 위의 예제에서 쓰레드는 sleep의 호출로 인하여 10초 동안 실행을 멈춤상태가 되고 10초 동안에도 while문은 isInterrupted의 값이 true가 될때까지 의미없이 계속 반복한다. 이런 상태를 바쁜 대기상태(busy-waiting)라고 하며 yield를 호출해서 남은 실행시간을 반복문에서 낭비하지 않고 다른 쓰레드에게 양보하게 된다.
    while (true){
    	if(!isInterrupted()){
        System.out.println(t--);
        try{
            Thread.sleep(10000);
        } catch(InterruptedException e) { 
        	interrupt();
            break;
            }
        } else { Thread.yield(); }	
    }

     

    👉 join()

    • 다른 쓰레드의 작업을 기다린다.
    • 쓰레드 자신이 하던 작업을 잠시 멈추고 다른 쓰레드가 지정된 시간동안 작업을 수행하도록 할때 join()을 사용한다.
    • 매개 변수 (long millis) (long millis, int nanos) 로 시간을 지정하지 않으면 작업을 끝낼때 까지 기다리게 된다.
    • 데몬 쓰레드와 멀티 쓰레드의 복합적인 예제를 만들어 학습했다.
     public class ThreadStudy2 {
        static long startTime = 0;
        public static void main(String args[]) {
            ThreadEx_1 th1 = new ThreadEx_1();
            ThreadEx_2 th2 = new ThreadEx_2();
            Thread dt1 = new Thread(new Daemon_1());
            dt1.setDaemon(true);// setDaemon 은 시작 전에 호출해야된다.
            dt1.start();  // 데몬 쓰레드 동작 시작
    
            th1.start();
            th2.start();
            startTime = System.currentTimeMillis();
    
            try {
                th1.join(); // th1 끝날때 까지 기다린다.
                System.out.println("////");
            } catch(InterruptedException e) {}
            try {
                th2.join(); // th2 끝날때 까지 기다린다.
                System.out.println("@@@@");
            } catch(InterruptedException e) {}
    
            System.out.println("Time :" + (System.currentTimeMillis() - ThreadStudy2.startTime));
        } // main
    }
    class ThreadEx_1 extends Thread {
        public void run() {
            for(int i=0; i < 20; i++) {
                try{
                    Thread.sleep(300);
                } catch(InterruptedException e) {}
                System.out.print("*");
                if(i==5) Daemon_1.autoSave =true;
            }
        } 
    }
    
    class ThreadEx_2 extends Thread {
        public void run() {
            for(int i=0; i < 30; i++) {
                try{
                    Thread.sleep(300);
                } catch(InterruptedException e) {}
                System.out.print("=");
                if(i==5) Daemon_1.autoSave =true;
            }
        } // run()
    }
    class Daemon_1 implements Runnable {
        public static boolean autoSave = false;
    
        public void run() {
            while (true){
                try {
                    Thread.sleep(3*1000);
                }catch (InterruptedException e){}
    
                if(autoSave) save();
            }
        }
        public void save() {
            System.out.println("자동 저장됨.");
        }
    }
    • ThreadEx_1, ThreadEx_2 일반 쓰레드와 Daemon_1 데몬 쓰레드를 정의하고, main 메소드에서는 멀티 쓰레드가 동작이 끝날때까지 시간을 카운터 하고 있으며, 멀티 쓰레드가 동작을 마치게 되면 카운터 한 시간을 출력하기 위해서 join() 메소드를 활용하여 main 메소드의 동작을 멈추게 했다.
    • 데몬 쓰레드는 일반 쓰레드가 동작하면서 3초마다 호출되어 출력하도록 작성하였다.
    • 여기서 join() 메소드를 호출하여 main 메소드의 동작을 멈추고 일반 쓰레드가 동작을 마칠때까지 기다리게 해주는 역할을 하고 있다.
    • main 메소드에서 join()이 호출되어 동작이 멈춘다는 것은, public 클래스도 하나의 쓰레드로 동작하고 있다는 것을 확인할수 있다.
    출력값
    
    =*=*=**=*=*=*=*=*=자동 저장됨.
    =*=*=*=*=**==*=*=**=자동 저장됨.
    *=////                         <- ThreadEx_1 종료
    =========자동 저장됨.
    =@@@@                          <- ThreadEx_2 종료
    Time :9283                     <- 모두 종료 후 출력
    • 출력값을 보면, ThreadEx_1이 종료되고, 호출한 th1.join() 메소드 다음줄의 코드가 실행된 것을 볼수 있다.
    • ThreadEx_1 쓰레드가 종료되고 , th1.join() 메소드가 실행 될때까지 main 메소드가 멈춰 있었던 것을 확인할수 있다.

    'Language > JAVA' 카테고리의 다른 글

    Java Lambda Expression(람다식)_01  (1) 2022.09.07
    Java Thread_03  (0) 2022.09.05
    Java Thread_01  (0) 2022.09.04
    Java Annotation  (1) 2022.09.04
    Java 열거형  (0) 2022.09.03
      'Language/JAVA' 카테고리의 다른 글
      • Java Lambda Expression(람다식)_01
      • Java Thread_03
      • Java Thread_01
      • Java Annotation
      sussa
      sussa
      Efforts to take on a challenge

      티스토리툴바