SEB TILπŸ‘

TIL - μŠ€λ ˆλ“œ, JVM, GC

Jeein0313 2023. 3. 10. 14:18

μ˜€λŠ˜μ€ μŠ€λ ˆλ“œμ˜ μ •μ˜μ™€ 생성 및 μ‹€ν–‰ 방법에 λŒ€ν•΄ ν•™μŠ΅ν–ˆλ‹€. ν•™λΆ€ λ•Œλ„ κ³΅λΆ€ν–ˆλ˜ λ‚΄μš©μΈλ°, κ·Έλ•Œλ„ 쑰금 λ‚―μ„€μ—ˆλ˜ 기얡이 λ‚œλ‹€. κ°„λ‹¨νžˆ 리뷰해 보도둝 ν•˜κ² λ‹€.

 

 

β“μŠ€λ ˆλ“œλž€ 무엇인가

μž‘μ—… κ΄€λ¦¬μžλ₯Ό 듀어가보면  ν˜„μž¬ μ‹€ν–‰ 쀑인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 즉, ν”„λ‘œμ„ΈμŠ€ λͺ©λ‘μ„ 확인할 수 μžˆλ‹€. μ΄λ•Œ, ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ‹€ν–‰λ˜λŠ” μ†ŒμŠ€ μ½”λ“œμ˜ μ‹€ν–‰ 흐름을 μŠ€λ ˆλ“œλΌ ν•œλ‹€.

 

 

❓메인 μŠ€λ ˆλ“œλž€?

μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‹€ν–‰ν•˜λ©΄ κ°€μž₯ λ¨Όμ € μ‹€ν–‰λ˜λŠ” μŠ€λ ˆλ“œλ‘œ 메인 μŠ€λ ˆλ“œκ°€ main λ©”μ„œλ“œλ₯Ό μ‹€ν–‰μ‹œμΌœ μ€€λ‹€(맀일 μ‚¬μš©ν•˜λŠ” public static void main~). 메인 μŠ€λ ˆλ“œλŠ” main λ©”μ„œλ“œμ˜ μ½”λ“œλ₯΄λ₯Ό μ²˜μŒλΆ€ν„° 끝가지 순차적으둜 μ‹€ν–‰μ‹œν‚€λ©°, μ½”λ“œμ˜ 끝을 λ§Œλ‚˜κ±°λ‚˜ return문을 λ§Œλ“œλ©΄ 싀행을 μ’…λ£Œν•œλ‹€. μ΄λ ‡κ²Œ 메인 μŠ€λ ˆλ“œλ§Œ κ°€μ§€λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μ‹±κΈ€ μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€λΌ ν•˜λ©°, 메인 μŠ€λ ˆλ“œμ—μ„œ 또 λ‹€λ₯Έ μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•΄μ„œ μ‹€ν–‰μ‹œν‚¨λ‹€λ©΄ ν•΄λ‹Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ©€ν‹° μŠ€λ ˆλ“œλ‘œ λ™μž‘ν•˜κ²Œ λœλ‹€.

 

 

β“μž‘μ—… μŠ€λ ˆλ“œ 생성과 μ‹€ν–‰

μžλ°”λŠ” 객체지ν–₯ μ–Έμ–΄λ‘œ λͺ¨λ“  μ½”λ“œλ₯Ό 클래슀 μ•ˆμ— μž‘μ„±ν•΄μ•Ό ν•œλ‹€. λ”°λΌμ„œ μŠ€λ ˆλ“œκ°€ μˆ˜ν–‰ν•  μ½”λ“œλ„ 클래슀 내뢀에 μž‘μ„±ν•΄μ£Όμ–΄μ•Ό ν•˜λ©°, run()μ΄λΌλŠ” λ©”μ„œλ“œλ‚΄μ— μŠ€λ ˆλ“œκ°€ μ²˜λ¦¬ν•  μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ•Ό ν•œλ‹€.

 

run() λ©”μ„œλ“œλŠ” Runnable μΈν„°νŽ˜μ΄μŠ€μ™€ Thread ν΄λž˜μŠ€μ— μ •μ˜λ˜μ–΄μ Έ μžˆλ‹€.

λ³΄μ΄λŠ” κ²ƒμ²˜λŸΌ Thread ν΄λž˜μŠ€λŠ” Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό implements ν•˜κ³  μžˆλ‹€.

λ”°λΌμ„œ μš°λ¦¬λŠ” λ‹€μŒ  2κ°€μ§€ λ°©λ²•μœΌλ‘œ μž‘μ—… μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ κ°€λŠ₯ν•˜λ‹€.

 

1. Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ κ°μ²΄μ—μ„œ run()을 κ΅¬ν˜„ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν•˜λŠ” 방법

2. Thread 클래슀λ₯Ό 상속받은 ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ run()을 κ΅¬ν˜„ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν•˜λŠ” 방법

 

 

 

방법1)

public class RunnableThreadExample {
    public static void main(String[] args) {
        //Runnable κ΅¬ν˜„ 객체λ₯Ό 인자둜 μ „λ‹¬ν•˜λ©΄μ„œ Thread 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν•˜μ—¬ μŠ€λ ˆλ“œ 생성
        Thread thread1 = new Thread(new ThreadTask1());
        thread1.start();
    }
}

class ThreadTask1 implements Runnable{
    public void run(){
        for(int i=0;i<100;i++){
            System.out.print("#");
        }
    }
}

 

 

방법2)

package codeStates.thread;

public class ThreadClassExample {
    public static void main(String[] args) {
        //Thread 클래슀λ₯Ό 상속받은 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό 생성
        ThreadTask2 thread2 = new ThreadTask2();

        thread2.start();

        for (int i = 0; i < 100; i++) System.out.print("@");
        
    }
}

//Thread 클래슀λ₯Ό μƒμ†λ°›λŠ” 클래슀 μž‘μ„±
class ThreadTask2 extends Thread{
    public void run(){
        for(int i=0;i<100;i++) System.out.print("#");
    }
}

 

 

또, 읡λͺ… 객체λ₯Ό μ‚¬μš©ν•΄μ„œλ„ μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.

 

 

 

방법3) Runnable 읡λͺ… κ΅¬ν˜„ 객체λ₯Ό ν™œμš©ν•œ μŠ€λ ˆλ“œ μƒμ„±ν•˜κ³  μ‹€ν–‰ν•˜κΈ°

package codeStates.thread;

//읡λͺ… 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œ 생성 및 μ‹€ν–‰
public class AnonymousObjectThreadExample {
    public static void main(String[] args) {
        
        //읡λͺ… Runnable κ΅¬ν˜„ 객체λ₯Ό ν™œμš©ν•˜μ—¬ μŠ€λ ˆλ“œ 생성
        Thread thread3=new Thread(new Runnable(){
            public void run(){
                for(int i=0;i<100;i++) System.out.print("#");
            }
        });

        thread3.start();

        for(int i=0;i<100;i++) System.out.print("@");
        
    }
}

 

 

방법4) Thread 읡λͺ… ν•˜μœ„ 객체λ₯Ό ν™œμš©ν•œ μŠ€λ ˆλ“œ 생성 및 μ‹€ν–‰

package codeStates.thread;

//읡λͺ… 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œ 생성 및 μ‹€ν–‰
public class AnonymousObjectThreadExample {
    public static void main(String[] args) {

        //2.Thread 읡λͺ… 객체λ₯Ό ν™œμš©ν•œ μŠ€λ ˆλ“œ 생성
        Thread thread4=new Thread(){
            public void run(){
                for (int i = 0; i < 100; i++) System.out.print("*");

            }
        };

        thread4.start();


    }
}

 

 

 

 

 

β“μŠ€λ ˆλ“œ λ™κΈ°ν™”λž€?

λ©€ν‹° μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ˜ 경우, 두 μŠ€λ ˆλ“œκ°€ λ™μΌν•œ 데이터λ₯Ό κ³΅μœ ν•˜κ²Œ λ˜μ–΄ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμœΌλ―€λ‘œ, 동기화 처리λ₯Ό ν•΄μ€˜μ•Ό ν•œλ‹€. μŠ€λ ˆλ“œ λ™κΈ°ν™”μ—λŠ” μž„κ³„μ˜μ—­κ³Ό λ½μ΄λΌλŠ” κ°œλ…μ΄ μžˆλŠ”λ° μš°μ„ , μž„κ³„μ˜μ—­μ€ μ˜€λ‘œμ§€ ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆλŠ” μ½”λ“œ μ˜μ—­μ„ λ§ν•˜λ©°, 락은 μž„κ³„ μ˜μ—­μ„ ν¬ν•¨ν•˜κ³  μž‡λŠ” 객체에 μ ‘κ·Όν•  수 μžˆλŠ” κΆŒν•œμ„ μ˜λ―Έν•œλ‹€. 즉, μž„κ³„ μ˜μ—­μœΌλ‘œ μ„€μ •λœ 객체가 λ‹€λ₯Έ μŠ€λ ˆλ“œμ— μ˜ν•΄ μž‘μ—…μ΄ 이루어지고 μžˆμ§€ μ•Šμ„ λ•Œ, μž„μ˜μ˜ μŠ€λ ˆλ“œ AλŠ” ν•΄λ‹Ή 객체에 λŒ€ν•œ 락을 νšλ“ν•˜μ—¬ μž„κ³„ μ˜μ—­μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€. μ΄λ•Œ, μŠ€λ ˆλ“œκ°€ Aκ°€ μž„κ³„ μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ μ€‘μΌλ•Œμ—λŠ” λ‹€λ₯Έ μŠ€λ ˆλ“œλ“€μ€ 락이 μ—†μœΌλ―€λ‘œ 이 객체의 μž„κ³„ μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μ—†λ‹€. 이후, μŠ€λ ˆλ“œ Aκ°€ μž„κ³„ μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό λͺ¨λ‘ μ‹€ν–‰ν•˜λ©΄ 락을 λ°˜λ‚©. μ΄λ•Œ λΆ€ν„°λŠ” λ‹€λ₯Έ μŠ€λ ˆλ“œλ“€ 쀑 ν•˜λ‚˜κ°€ 락을 νšλ“ν•˜μ—¬ μž„κ³„ μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ κ°€λŠ₯ν•œ 것이닀. 즉, μš°λ¦¬λŠ” μž„κ³„ μ˜μ—­μ„ μ„€μ •ν•˜μ—¬ μŠ€λ ˆλ“œ 동기화 처리λ₯Ό ν•  수 μžˆλ‹€.

 

동기화 예제 μ½”λ“œ)

package codeStates.thread;

//μŠ€λ ˆλ“œ 동기화 예제
public class ThreadSynchronizationExample {
    public static void main(String[] args) {
        Runnable threadTask3 = new ThreadTask3();
        Thread thread3_1 = new Thread(threadTask3);
        Thread thread3_2 = new Thread(threadTask3);

        thread3_1.setName("κΉ€μ½”λ”©");
        thread3_2.setName("λ°•μžλ°”");

        thread3_1.start();
        thread3_2.start();
    }
}

class Account{
    private int balance = 1000;

    public int getBalance(){
        return balance;
    }
    //동기화 처리 1) λ©”μ„œλ“œ 전체λ₯Ό μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •
//    public synchronized boolean withdraw(int money){
//        if(balance>=money){
//            try{ Thread.sleep(1000);} catch(Exception error){}
//            balance -= money;
//            return true;
//        }
//        return false;
//    }

    //동기화 처리 2) νŠΉμ •ν•œ μ˜μ—­μ„ μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •ν•˜κΈ°
    public boolean withdraw(int money){
        synchronized (this){
            if(balance>=money){
                try{ Thread.sleep(1000);} catch(Exception error){}
                balance -= money;
                return true;
            }
        }
        return false;
    }
}

class ThreadTask3 implements Runnable {
    Account account = new Account();

    @Override
    public void run() {
        while(account.getBalance()>0){
            //100~300μ›μ˜ μΈμΆœκΈˆμ„ 랜덀으둜 정함.
            int money = (int) (Math.random() * 3 + 1) * 100;

            //withdrawλ₯Ό μ‹€ν–‰μ‹œν‚€λŠ” λ™μ‹œμ— μΈμΆœμ„±κ³΅ μ—¬λΆ€λ₯Ό λ³€μˆ˜μ— ν• λ‹Ή
            boolean denied = !account.withdraw(money);

            //인좜 κ²°κ³Ό 확인
            System.out.println(String.format("Withdraw %d원 By %s. Balancce : %d %s",
                    money, Thread.currentThread().getName(), account.getBalance(),denied));
        }
    }
}

 

 

 

 

β“μŠ€λ ˆλ“œμ˜ μƒνƒœμ™€ μ‹€ν–‰ μ œμ–΄

μ•žμ—μ„œ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 데 start() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν–ˆμœΌλ‚˜, μ—„λ°€νžˆ λ§ν•˜λ©΄ start()λŠ” μŠ€λ ˆλ“œλ₯Ό λ°”λ‘œ μ‹€ν–‰μ‹œν‚€λŠ” λ©”μ„œλ“œλŠ” μ•„λ‹ˆλ‹€. start()λŠ” μŠ€λ ˆλ“œμ˜ μƒνƒœλ₯Ό 'μ‹€ν–‰ λŒ€κΈ° μƒνƒœ'둜 λ§Œλ“€μ–΄μ£ΌλŠ” λ©”μ„œλ“œμ΄λ©°, μ–΄λ–€ μŠ€λ ˆλ“œκ°€ start()에 μ˜ν•΄ μ‹€ν–‰ λŒ€κΈ° μƒνƒœκ°€ 되면 μš΄μ˜μ²΄μ œκ°€ μ μ ˆν•œ λ•Œμ— μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œμΌœ μ€€λ‹€.

κ·Έ 밖에 μŠ€λ ˆλ“œ μ‹€ν–‰ μ œμ–΄ λ©”μ„œλ“œ λͺ‡ κ°€μ§€λ₯Ό μ•Œμ•„λ³΄μž.

 

  • static void sleep(long  millis) : milliSecond λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μž μ‹œ 멈좀. μ§€μ •ν•œ μ‹œκ°„λ§ŒνΌ μ •ν™•νžˆ μŠ€λ ˆλ“œκ°€ μ€‘μ§€λ˜λŠ” 것은 μ•„λ‹ˆκ³ , μ•½κ°„μ˜ μ˜€μ°¨κ°€ μžˆλ‹€. sleep()에 μ˜ν•΄ μΌμ‹œμ •μ§€λœ μŠ€λ ˆλ“œλŠ” 인자둜 μ „λ‹¬ν•œ μ‹œκ°„ 만큼의 μ‹œκ°„μ΄ κ²½κ³Όλ˜κ±°λ‚˜, interrupt()λ₯Ό ν˜ΈμΆœν•œ 경우 μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€ν•œλ‹€. (interrupt()κ°€ ν˜ΈμΆœλ˜λŠ” 기본적으둜 μ˜ˆμ™Έκ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ—, sleep()을 μ‚¬μš©ν•  λ•Œμ—λŠ” try..catch문으둜 감싸주어야 ν•œλ‹€.)
  • void interrupt() : μΌμ‹œ 쀑지 μƒνƒœμΈ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ 볡귀. sleep(), wait(), join()에 μ˜ν•΄ μΌμ‹œ μ •μ§€ μƒνƒœμ— μžˆλŠ” μŠ€λ ˆλ“œλ“€μ„ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€μ‹œν‚¨λ‹€. 
  • static void yield() : λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ μžμ‹ μ˜ μ‹€ν–‰ μ‹œκ°„μ„ μ–‘λ³΄ν•œλ‹€. 예λ₯Ό λ“€μ–΄, 운영체제의 μŠ€μΌ€μ€„λŸ¬μ— μ˜ν•΄ 3초λ₯Ό 할당받은 μŠ€λ ˆλ“œ Aκ°€ 1초 λ™μ•ˆ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ‹€κ°€ yieldλ₯Ό ν˜ΈμΆœν•˜λ©΄ 남은 μ‹€ν–‰ μ‹œκ°„ 2μ΄ˆλŠ” λ‹€μŒ μŠ€λ ˆλ“œμ—κ²Œ μ–‘λ³΄λœλ‹€. 
  • void join(), void join(long millis) : join()은 νŠΉμ • μŠ€λ ˆλ“œκ°€ μž‘μ—…ν•˜λŠ” λ™μ•ˆμ— μžμ‹ μ„ μΌμ‹œ 쀑지 μƒνƒœλ‘œ λ§Œλ“œλŠ” μƒνƒœ μ œμ–΄ λ©”μ„œλ“œμ΄λ‹€. 인자둜 μ‹œκ°„μ„ λ°€λ¦¬μ΄ˆ λ‹¨μœ„λ‘œ 전달할 수 있으며, μ „λ‹¬ν•œ 인자만큼의 μ‹œκ°„μ΄ κ²½κ³Όν•˜κ±°λ‚˜, interrupt()κ°€ ν˜ΈμΆœλ˜κ±°λ‚˜, join() 호좜 μ‹œ μ§€μ •ν–ˆλ˜ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ λͺ¨λ“  μž‘μ—…μ„ 마치면 λ‹€μ‹œ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€ν•œλ‹€.
  • void wait()(Object에 μœ„μΉ˜), void notify() (Object에 μœ„μΉ˜) : μŠ€λ ˆλ“œ A와 μŠ€λ ˆλ“œ Bκ°€ 곡유 객체λ₯Ό 두고 ν˜‘μ—…ν•˜λŠ” μƒν™©μ—μ„œ λ¨Όμ € μŠ€λ ˆλ“œAκ°€ 곡유 객체의 μžμ‹ μ˜ μž‘μ—…μ„ μ™„λ£Œν•˜κ³  B와 κ΅μ²΄ν•˜κΈ° μœ„ν•΄ notify()λ₯Ό ν˜ΈμΆœν•œλ‹€. notify()κ°€ 호좜되면 μŠ€λ ˆλ“œ Bκ°€ μ‹€ν–‰ λŒ€κΈ° μƒνƒœκ°€ 되며, κ³§ μ‹€ν–‰λœλ‹€. μ΄μ–΄μ„œ μŠ€λ ˆλ“œ AλŠ” wait()λ₯Ό ν˜ΈμΆœν•˜μ—¬ 자기 μžμ‹ μ„ μΌμ‹œμ •μ§€ μƒνƒœλ‘œ λ§Œλ“ λ‹€. 이후 μŠ€λ ˆλ“œBκ°€ μž‘μ—…μ„ μ™„λ£Œν•˜λ©΄ notify()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μž‘μ—…μ„ μ€‘λ‹¨ν•˜κ³  있던 μŠ€λ ˆλ“œ Aλ₯Ό λ‹€μ‹œ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€μ‹œν‚¨ ν›„, wait()λ₯Ό ν˜ΈμΆœν•˜μ—¬ 자기 μžμ‹ μ˜ μƒνƒœλ₯Ό μΌμ‹œ μ •μ§€ μƒνƒœλ‘œ μ „ν™˜ν•œλ‹€.

 

 

 

 

JVMκ³Ό GCλŠ” λ‹€μŒ ν¬μŠ€νŒ…μ—μ„œ 더 μžμ„Ένžˆ μ¨λ‘μ—ˆλ‹€.

 

 

 

 

 

https://nothing-is-on-my-way.tistory.com/52

 

πŸ’œJVM와 GC(Garbage Collector)

μžλ°”λŠ” μš΄μ˜μ²΄μ œμ— 독립적인 언어이며, μ΄λŠ” JVM으둜 인해 κ°€λŠ₯ν•˜λ‹€. πŸ™„ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄κ°€ μš΄μ˜μ²΄μ œμ— λ…λ¦½μ μ΄λΌλŠ” 것은 무슨 뜻일까? λ¨Όμ € μ–΄λ– ν•œ ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰λ˜κΈ° μœ„ν•΄μ„œλŠ” OS둜 λΆ€ν„° CPU

nothing-is-on-my-way.tistory.com