ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] μžλ°” μ“°λ ˆλ“œ 생성(Thread, Runnable)
    Android/Java 2021. 2. 2. 14:52
    λ°˜μ‘ν˜•
    • 이 글은 "μžλ°” 온라인 μŠ€ν„°λ””" κ³΅λΆ€ν•œ λ‚΄μš©μ„ μ •λ¦¬ν•˜μ—¬ μ“΄ κΈ€μž…λ‹ˆλ‹€.

    Process vs Thread

    μžλ°”μ˜ μ“°λ ˆλ“œλ₯Ό μ„€λͺ…ν•˜κΈ° 이전에 ν”„λ‘œμ„ΈμŠ€μ™€ μ“°λ ˆλ“œμ˜ 차이에 λŒ€ν•΄ κ°„λž΅ν•˜κ²Œλ‚˜λ§ˆ μ•Œ ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€.

    Process

    ν”„λ‘œμ„ΈμŠ€μ˜ 사전적 μ •μ˜λ‘œλŠ” μ‹€ν–‰ 쀑인 ν”„λ‘œκ·Έλž¨μ„ λœ»ν•˜κ²Œ λ©λ‹ˆλ‹€.
    μœˆλ„μš°μ—μ„œ μ €μž₯μž₯μΉ˜μ— μ €μž₯된 μƒνƒœλ₯Ό ν”„λ‘œκ·Έλž¨μ΄λΌκ³  ν•˜κ³  더블클릭을 톡해 ν”„λ‘œκ·Έλž¨μ΄ λ©”λͺ¨λ¦¬ 곡간에 μ˜¬λΌμ™€ 싀행쀑인 ν”„λ‘œκ·Έλž¨ μΈμŠ€ν„΄μŠ€λ₯Ό ν”„λ‘œμ„ΈμŠ€λΌκ³  ν•©λ‹ˆλ‹€.

    Thread

    ν•œ ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ λ™μž‘λ˜λŠ” μ‹€ν–‰λ‹¨μœ„λ₯Ό λœ»ν•˜κ²Œ λ©λ‹ˆλ‹€.
    크둬 λΈŒλΌμš°μ €λΌλŠ” ν”„λ‘œμ„ΈμŠ€μ—μ„œ μœ νŠœλΈŒμ— μ ‘μ†ν•˜μ—¬ λ™μ˜μƒμ„ μ‹œμ²­ν•  λ•Œ 유튜브 데이터λ₯Ό λ‹€μš΄λ‘œλ“œ λ°›μœΌλ©΄μ„œ λ™μ˜μƒμ΄ μ‹€ν–‰λ˜λŠ” μž‘μ—…μ΄ λ™μ‹œμ— μ΄λ£¨μ–΄μ§€λŠ” 것도 μ“°λ ˆλ“œλ₯Ό 톡해 κ°€λŠ₯ν•˜κ²Œ λ©λ‹ˆλ‹€.



    Thread 생성

    • μžλ°”μ—μ„œ Threadλ₯Ό μƒμ„±ν•˜λŠ” 방법은 두 가지가 μ‘΄μž¬ν•©λ‹ˆλ‹€.
    • ν•˜λ‚˜λŠ” Thread 클래슀λ₯Ό 상속받아 run λ©”μ†Œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”© ν•˜λŠ” 것과 Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό implements ν•˜μ—¬ run λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

    Thread 클래슀

    public class MyThread extends Thread{
        int num;
    
        public MyThread() {
            this.num = 0;
        }
    
        public MyThread(int num) {
            this.num = num;
        }
    
        @Override
        public void run() {
            System.out.println(this.num + " thread start");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(this.num +" thread end");
        }
    }

    Thread 클래슀λ₯Ό 상속받아 μ»€μŠ€ν…€ Thread 클래슀λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. run λ©”μ†Œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”© ν•˜μ—¬ μžμ‹ μ΄ μ›ν•˜λŠ” μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    public class Main {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            myThread.start();
            System.out.println("main end");
        }
    }

    μ½”λ“œ μˆœμ„œλŒ€λ‘œλΌλ©΄ thread start와 endκ°€ 좜λ ₯된 이후에 main endκ°€ 좜λ ₯λ˜μ–΄μ•Ό ν•˜μ§€λ§Œ main endκ°€ λ¨Όμ € 좜λ ₯된 λͺ¨μŠ΅μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
    즉, 메인 μ“°λ ˆλ“œμ™€ λ‹€λ₯Έ μƒˆλ‘œμš΄ μ“°λ ˆλ“œκ°€ μƒμ„±λ˜μ–΄ λ™μ‹œμ— μ‹€ν–‰λ˜μ—ˆλ‹€λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

    public class Main {
        public static void main(String[] args) {
            for(int i=1;i<=10;i++){
                MyThread myThread = new MyThread(i);
                myThread.start();
            }
            System.out.println("main end");
        }
    }

    μ •ν™•ν•œ μ“°λ ˆλ“œ λ™μž‘μ„ ν™•μΈν•˜κΈ° μœ„ν•΄ 각 μ“°λ ˆλ“œμ— 번호λ₯Ό λΆ™μ—¬μ„œ ν™•μΈν•΄λ΄€μŠ΅λ‹ˆλ‹€.

    λͺ¨λ“  μ“°λ ˆλ“œλ“€μ€ 순차적으둜 μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌ λ¬΄μž‘μœ„λ‘œ μ‹€ν–‰λ˜λŠ” μ΄μœ λŠ” λ™μ‹œμ μœΌλ‘œ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. Thread ν΄λž˜μŠ€μ—μ„œλŠ” start λ©”μ†Œλ“œμ™€ run λ©”μ†Œλ“œλ“€μ΄ λ‘˜ λ‹€ μ‘΄μž¬ν•˜λŠ”λ° start λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ™œ run λ©”μ†Œλ“œκ°€ μ‹€ν–‰λ˜λŠ”μ§€λŠ” 뒀에 μ„€λͺ…ν•˜λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

    Runnable μΈν„°νŽ˜μ΄μŠ€

    Threadλ₯Ό 생성할 λ•Œ Thread 클래슀λ₯Ό μƒμ†λ°›λŠ” 방법도 μžˆμ§€λ§Œ Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법도 μ‘΄μž¬ν•©λ‹ˆλ‹€.

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }

    Runnable μΈν„°νŽ˜μ΄μŠ€λŠ” run λ©”μ†Œλ“œλ₯Ό 무쑰건 κ΅¬ν˜„ν•˜λΌκ³  κ°•μ œν•œ μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€.

    참고둜 @FunctionalInterfaceλŠ” μΈν„°νŽ˜μ΄μŠ€ 내뢀에 λ©”μ†Œλ“œκ°€ 1개 μžˆλ‹€κ³  μ•Œλ €μ£ΌλŠ” 메타데이터(주석)μž…λ‹ˆλ‹€.

    public class MyRunnable implements Runnable {
        int num;
    
        public MyRunnable() {
            this.num = 0;
        }
    
        public MyRunnable(int num) {
            this.num = num;
        }
    
        @Override
        public void run() {
            System.out.println(this.num + " thread start");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(this.num +" thread end");
        }
    }

    이 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•œ MyRunnable ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
    Thread의 ν΄λž˜μŠ€μ™€ λ™μΌν•˜κ²Œ runλ©”μ†Œλ“œλŠ” thread start와 end μ‹œμ μ„ 좜λ ₯ν•˜λ„λ‘ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

    public class Main {
        public static void main(String[] args) {
            for(int i=1;i<=10;i++){
                Thread thread = new Thread(new MyRunnable(i));
                thread.start();
            }
            System.out.println("main end");
        }
    }

    Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€λŠ” Thread의 λ§€κ°œλ³€μˆ˜λ‘œ λ„£μ–΄ Threadλ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€. 이후 thread.start()λ₯Ό ν•˜κ²Œ 되면 Thread ν΄λž˜μŠ€μ™€ λ™μΌν•˜κ²Œ μ“°λ ˆλ“œκ°€ λ™μ‹œμ— μ‹€ν–‰λ˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

    Thread Class 와 Runnable Interface 비ꡐ

    Thread 클래슀λ₯Ό μƒμ†ν•˜κ±°λ‚˜ Runnable Interfaceλ₯Ό κ΅¬ν˜„ν•˜μ—¬ λ§Œλ“  μŠ€λ ˆλ“œλŠ” run λ©”μ„œλ“œ μ½”λ“œμ˜ μ‹€ν–‰κ³Ό μ„±λŠ₯은 λ™μΌν•©λ‹ˆλ‹€. λ‹€λ§Œ κ΅¬ν˜„κ³Όμ •μ—μ„œλ§Œ 차이가 λ‚©λ‹ˆλ‹€.객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 상속은 λΆ€λͺ¨μ˜ κΈ°λŠ₯을 λ¬Όλ €λ°›μ•„ μž¬μ‚¬μš©ν•˜κ±°λ‚˜, μž¬μ •μ˜λ₯Ό ν•˜κ³  μƒˆλ‘œμš΄ κΈ°λŠ₯듀은 μΆ”κ°€ν•˜μ—¬ ν™•μž₯ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μžλ°”μ˜ 닀쀑상속이 λΆˆκ°€λŠ₯점을 μƒκ°ν•˜λ©΄ Thread 클래슀의 run λ©”μ†Œλ“œ ν•˜λ‚˜λ•Œλ¬Έμ— 상속기λŠ₯을 μ‚¬μš©ν•˜λŠ” 것은 λΉ„νš¨μœ¨μ μž…λ‹ˆλ‹€.

    이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ μŠ€λ ˆλ“œ 생성 μ‹œ λ°˜λ“œμ‹œ κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” run λ©”μ†Œλ“œλ₯Ό Thread ν΄λž˜μŠ€μ™€ λΆ„λ¦¬ν•˜κ³  κ΅¬ν˜„μ„ κ°•μ œν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 이것이 λ°”λ‘œ Runnable μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€. λ§Œμ•½, Thread 클래슀의 또 λ‹€λ₯Έ κΈ°λŠ₯을 ν™•μž₯ν•˜κ±°λ‚˜ μž¬μ •μ˜λ₯Ό ν•΄μ•Όν•  경우라면 Runnable μΈν„°νŽ˜μ΄μŠ€ λŒ€μ‹  Thread 클래슀λ₯Ό μƒμ†ν•˜λŠ”κ²Œ 더 효과적일 수 μžˆμŠ΅λ‹ˆλ‹€.

    λ”°λΌμ„œ, Thread 클래슀 κΈ°λŠ₯의 ν™•μž₯ 여뢀에 따라 Thread 클래슀λ₯Ό 상속받을 것인지, Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  것인지 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.

     

    μ™œ start λ©”μ†Œλ“œμΌκΉŒ?

    μ €λŠ” μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜μ—¬ start λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν–ˆλŠ”λ° μ™œ run λ©”μ†Œλ“œκ°€ ν˜ΈμΆœλ˜λŠ”μ§€ μ΄μœ κ°€ κΆκΈˆν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.

        public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }

    λ‚΄λΆ€ν•¨μˆ˜μ— start0() λ©”μ†Œλ“œκ°€ μžˆλŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 이 λ©”μ†Œλ“œλŠ” λ„€μ΄ν‹°λΈŒ ν•¨μˆ˜λ‘œ λ‚΄λΆ€μ μœΌλ‘œ run λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ„λ‘ κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

    두 ν•¨μˆ˜μ˜ 차이점을 λ§ν•˜κΈ° 전에 ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬ ꡬ쑰에 λŒ€ν•΄ μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€.
    μœ„μ˜ κ·Έλ¦Όμ—μ„œ μ™Όμͺ½μ€ 단일 μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€, 였λ₯Έμͺ½μ€ 닀쀑 μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μž…λ‹ˆλ‹€.

    • Heap : λ™μ μœΌλ‘œ μƒμ„±ν•˜λŠ” λ³€μˆ˜λ₯Ό λ‹΄λŠ” λ©”λͺ¨λ¦¬
    • Code : μ½”λ“œ μ˜μ—­ λ©”λͺ¨λ¦¬
    • Static : 정적 λ³€μˆ˜ or 클래슀 λ³€μˆ˜λ₯Ό λ‹΄λŠ” λ©”λͺ¨λ¦¬
    • Stack : λ©”μ†Œλ“œ λ‚΄ 지역 λ³€μˆ˜, μž„μ‹œλ³€μˆ˜λ₯Ό λ‹΄λŠ” λ©”λͺ¨λ¦¬

    닀쀑 μŠ€λ ˆλ“œλŠ” Heap, Code, Static μ˜μ—­μ€ κ³΅μœ ν•˜μ§€λ§Œ μŠ€λ ˆλ“œ λ³„λ‘œ 각기 λ‹€λ₯Έ Stack μ˜μ—­μ΄ μ‘΄μž¬ν•©λ‹ˆλ‹€.
    Thread 클래슀의 run λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 것은 λ‹¨μˆœνžˆ μ˜€λ²„λΌμ΄λ”©μ„ ν•œ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것일 λΏμž…λ‹ˆλ‹€. 즉, 메인 μŠ€λ ˆλ“œμ—μ„œμ˜ Stack μ˜μ—­μ„ 차지 ν•˜μ—¬ λ©”μ†Œλ“œκ°€ λλ‚˜μ§€ μ•ŠμœΌλ©΄ λ‹€λ₯Έ λ©”μ†Œλ“œκ°€ μ‹€ν–‰λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— 순차적으둜 진행될 수 밖에 μ—†μŠ΅λ‹ˆλ‹€.

    ν•˜μ§€λ§Œ start λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 것은 JVM은 μŠ€λ ˆλ“œλ₯Ό μœ„ν•œ Stack μ˜μ—­μ„ μƒˆλ‘œ λ§Œλ“€κΈ° λ•Œλ¬Έμ— run λ©”μ†Œλ“œ ν˜ΈμΆœκ³ΌλŠ” λ‹€λ₯΄κ²Œ λ…λ¦½μ μœΌλ‘œ λ™μž‘μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.

    λ°˜μ‘ν˜•
Designed by Tistory.