BackEnd🧡

TIL - μŠ€λ ˆλ“œ(Thread)

hae02y 2023. 5. 12. 14:55
λ°˜μ‘ν˜•

 

πŸ‘€Today...


ν”„λ‘œμ„ΈμŠ€μ™€ μŠ€λ ˆλ“œκ°€ 같은 뜻이라고 μƒκ°ν•΄μ™”μ—ˆλŠ”λ° μ΄λ²ˆμ— μ°Ύμ•„λ³΄λ©΄μ„œ λ‘˜μ˜ 차이점에 λŒ€ν•΄μ„œ μ•Œκ²Œλ˜μ—ˆλ‹€. μžλ°”μ˜ κ°œλ…μ„ κ³΅λΆ€ν•˜λŠ” κ³Όμ •μ΄μ—¬μ„œ μžμ„Έν•˜κ²Œ λ‹€λ£¨μ§€λŠ” λͺ»ν•˜μ§€λ§Œ μ‹œκ°„μ΄ λ λ•Œ ν•œλ²ˆλ” μžμ„Έν•˜κ²Œ 곡뢀해봐야겠닀.

 

 

β˜•μ˜€λŠ˜μ˜ TIL(Today I Learn)


μŠ€λ ˆλ“œλž€?

ν”„λ‘œμ„ΈμŠ€ : 싀행쀑인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ (데이터 + μ»΄ν“¨ν„°μžμ› + μŠ€λ ˆλ“œ)

μŠ€λ ˆλ“œ : μ½”λ“œμ˜ μ‹€ν–‰ 흐름

일반적으둜 ν•œν”„λ‘œκ·Έλž¨μ€ ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ₯Ό 가지고 μžˆμ§€λ§Œ, λ‘˜ μ΄μƒμ˜ μŠ€λ ˆλ“œλ₯Ό λ™μ‹œμ— μ‹€ν–‰ν•˜λŠ” 것도 κ°€λŠ₯ν•˜λ‹€. 이런 방식을 λ©€ν‹° μŠ€λ ˆλ“œλΌκ³  ν•œλ‹€. λ©€ν‹°ν”„λ‘œμ„ΈμŠ€λŠ” 각 ν”„λ‘œμ„ΈμŠ€κ°€ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜λ©° 각각 λ³„κ°œμ˜ λ©”λͺ¨λ¦¬λ₯Ό μ°¨μ§€ν•˜μ§€λ§Œ, λ©€ν‹°μŠ€λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€ λ‚΄μ˜ λ©”λͺ¨λ¦¬λ₯Ό κ³΅μœ ν•΄μ„œ μ‚¬μš©ν•œλ‹€. 단 λ©€ν‹°μŠ€λ ˆλ“œλŠ” 어떀것이 λ¨Όμ € 싀행될지 μˆœμ„œλ₯Ό μ•Œμˆ˜κ°€ μ—†λ‹€.

 

# μŠ€λ ˆλ“œμ˜ μ’…λ₯˜

1. μ‚¬μš©μž 레벨 μŠ€λ ˆλ“œ(User-Level Thread) : μ‚¬μš©μž 레벨의 라이브러리λ₯Ό 톡해 κ΅¬ν˜„λœλ‹€. λ™μΌν•œ λ©”λͺ¨λ¦¬ μ˜μ—­μ—μ„œ μŠ€λ ˆλ“œκ°€ 생성 및 κ΄€λ¦¬λ˜μ–΄ 속도가 λΉ λ₯΄λ‹€.

2. 컀널 레벨 μŠ€λ ˆλ“œ(Kernel-Level Thread) : μš΄μ˜μ²΄μ œκ°€ μ§€μ›ν•˜λŠ” μŠ€λ ˆλ“œκΈ°λŠ₯으둜 ꡬ성. 컀널이 μŠ€λ ˆλ“œμ˜ 생성 및 μŠ€μΌ€μ€„λ§ 등을 κ΄€λ¦¬ν•œλ‹€.

 

# λ©€ν‹°μŠ€λ ˆλ“œ λͺ¨λΈ

1. Many to One Model

2. One to One Model

3. Many to Many Model

 

 

μŠ€λ ˆλ“œ 생성 / μ‹€ν–‰

μžλ°”μ—μ„œλŠ” 기본적으둜 Main Threadκ°€ λ¨Όμ € μ‹€ν–‰λœλ‹€. μž‘μ„±μ‹œμ— main λ©”μ„œλ“œκ°€ μž‘μ„±λ˜μ•Ό 싀행이 κ°€λŠ₯ν•œκ²ƒ 이유λ₯Ό μ—¬κΈ°μ„œ μ•Œμˆ˜μžˆλ‹€. main μ΄μ™Έμ˜ μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν•˜λŠ” 방법은 2가지인데 κ΅¬λΆ„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

 

# Runnable μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„ν•œ κ°μ²΄μ—μ„œ run()

public class ThreadExample1 {
    public static void main(String[] args) {
        Runnable runnable = new ThreadExample(); //Runnable을 κ΅¬ν˜„ν•œ 객체 생성
        Thread thread1 = new Thread(runnable); //μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜μ—¬ 객체λ₯Ό λ‹΄λŠ”λ‹€.

        // μž‘μ—… μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰, run() λ‚΄λΆ€μ˜ μ½”λ“œλ₯Ό 처리
        thread1.start();
    }
}

class ThreadExample implements Runnable { //Runnable μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("#");
        }
    }

 

# Thread 클래슀λ₯Ό 상속받은 ν•˜μœ„ν΄λž˜μŠ€μ—μ„œ run()

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

        ThreadTask2 thread2 = new ThreadTask2(); //Threadλ₯Ό μƒμ†λ°›λŠ” ThreadExample 객체λ₯Ό 생성

        // μž‘μ—… μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰, run() λ‚΄λΆ€μ˜ μ½”λ“œλ₯Ό 처리
        thread2.start();
    }
}

class ThreadExample extends Thread {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("#");
        }
    }
}

 

# 읡λͺ…객체λ₯Ό κ΅¬ν˜„ν•˜μ—¬ μŠ€λ ˆλ“œ 생성 / μ‹€ν–‰

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

λ‹€μŒκ³Ό 같이 읡λͺ… 객체λ₯Ό ν™œμš©ν•˜μ—¬ ν•œλ²ˆμ— 생성도 κ°€λŠ₯ν•˜λ‹€.

 

 

μŠ€λ ˆλ“œ 이름 μ„€μ •

# μŠ€λ ˆλ“œ 이름 쑰회 및 μ„€μ •

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

            Thread thread = new Thread(new Runnable() {
                public void run() {
                    System.out.println("thread control");
                    System.out.println(Thread.currentThread().getName());  //μŠ€λ ˆλ“œ μΈμŠ€ν„΄μŠ€μ˜ μ£Όμ†Œμ–»κΈ°

                }
            });

            thread.start();
            System.out.println(Thread.currentThread().getName());


            System.out.println("thread.getName() = " + thread.getName()); //μŠ€λ ˆλ“œμ˜ 이름 μ–»κΈ°
            thread.setName("changed_name_thread"); //μŠ€λ ˆλ“œ 이름 μ„€μ •
            System.out.println("thread4.getName() = " + thread.getName());
        }
}

좜λ ₯

 

 

 

μŠ€λ ˆλ“œ 동기화

λ©€ν‹° μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ˜ 경우, μ—¬λŸ¬κ°œμ˜ μŠ€λ ˆλ“œκ°€ 같은 데이터λ₯Ό κ³΅μœ ν•˜κ²Œ λ˜μ–΄ λ¬Έμ œκ°€ λ°œμƒν• μˆ˜μžˆλ‹€. 이λ₯Ό λ°©μ§€ν•˜λŠ”κ²ƒμ΄ μŠ€λ ˆλ“œ 동기화이닀. 

 

# μž„κ³„μ˜μ—­(Critical section)

μž„κ³„μ˜μ—­μ€ μ˜€λ‘œμ§€ ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ μ½”λ“œλ₯Ό μ‹€ν–‰ ν• μˆ˜μžˆλŠ” μ½”λ“œ μ˜μ—­μ„ μ˜λ―Έν•œλ‹€.

 

# 락(Lock)

락은 μž„κ³„μ˜μ—­μ„ ν¬ν•¨ν•˜κ³  μžˆλŠ” 객체에 μ ‘κ·Όν•  수 μžˆλŠ” κΆŒν•œμ„ μ˜λ―Έν•œλ‹€.

 

μž„κ³„μ˜μ—­μœΌλ‘œ μ„€μ •λœ 객체가 λ‹€λ₯Έ μŠ€λ ˆλ“œμ— μ˜ν•œ μž‘μ—…μ΄ μ§„ν–‰λ˜κ³  μžˆμ§€ μ•Šμ„λ•Œ, λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ ν•΄λ‹Ή 객체에 λŒ€ν•œ 락을 νšλ“ν•˜κ³  μž„κ³„μ˜μ—­ λ‚΄λΆ€μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν• μˆ˜μžˆλ‹€. 동기화λ₯Ό μ‚¬μš©ν•˜λŠ” 방법은 μ—¬λŸ¬κ°€μ§€κ°€ μžˆλ‹€. ν•˜μ§€λ§Œ  μ—¬κΈ°μ„œλŠ” synchronized만 μ‚¬μš©ν•˜μ—¬ ν™•μΈν•΄λ³΄μž.

 

1. λ©”μ„œλ“œ 전체λ₯Ό μž„κ³„μ˜μ—­μœΌλ‘œ 지정

class Example {
	...
	public synchronized boolean example(int some) { //synchronized μ‚¬μš©
	    ...
	}
}

λ©”μ„œλ“œ λ°˜ν™˜νƒ€μž…μ˜ μ’ŒμΈ‘μ— synchronized ν‚€μ›Œλ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λ©”μ„œλ“œ 전체λ₯Ό μž„κ³„μ˜μ—­μœΌλ‘œ 섀정이 κ°€λŠ₯ν•˜λ‹€. μ΄λ ‡κ²Œ μ‚¬μš©ν•˜λ©΄ λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν• λ•Œ μŠ€λ ˆλ“œλŠ” λ©”μ„œλ“œκ°€ ν¬ν•¨λœ 객체의 락을 μ–»λŠ”λ‹€. 

 

2. νŠΉμ •ν•œ μ˜μ—­μ„ μž„κ³„μ˜μ—­μœΌλ‘œ 지정

class Example {
	...
	public boolean example(int some) {
	    synchronized (this) {  // synchronized ν‚€μ›Œλ“œμ™€ ν•¨κ»˜ μ†Œκ΄„ν˜Έ μ•ˆμ— ν•΄λ‹Ήμ˜μ—­μ΄ ν¬ν•¨λœ 객체 μ°Έμ‘°λ₯Ό λ„£μŒ
			   ... // 그리고 μ€‘κ΄„ν˜Έλ₯Ό μ—΄μ–΄ 블둝에 μ½”λ“œλ₯Ό μž‘μ„±
			   }
			   ...
			}
	}
}

μ΄λ ‡κ²Œ μ‚¬μš©ν•˜κ²Œ 되면 μž„κ³„μ˜μ—­μœΌλ‘œ μ„€μ •ν•œ λΈ”λ‘μ˜ μ½”λ“œκ°€ 싀행흐름에 μ§„μž…ν• λ•Œ λΈ”λ‘μ•ˆμ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ³  μžˆλŠ” μŠ€λ ˆλ“œκ°€ this에 ν•΄λ‹Ήν•˜λŠ” 객체의 락을 μ–»κ³ , λ°°νƒ€μ μœΌλ‘œ μž„κ³„μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•œλ‹€.

 

μŠ€λ ˆλ“œ μƒνƒœ

thread.start() //객체 μ‹€ν–‰λŒ€κΈ°

try { Thread.sleep(500); } catch (Exception error) {} //500 millisecondλ™μ•ˆ λ©ˆμΆ”κΈ°

thread.interrupt() // μΌμ‹œμ •μ§€ => μ‹€ν–‰λŒ€κΈ° λ³€κ²½

thread.yield() //λ‹€λ₯ΈμŠ€λ ˆλ“œμ— 싀행을 양보

thread.join() //μΌμ‹œμ€‘μ§€ μƒνƒœλ‘œ λ§Œλ“ λ‹€.

notify() // μ‹€ν–‰λŒ€κΈ°λ‘œ λ³€κ²½
wait() // μΌμ‹œ 정지 
// notify()와 wait()λŠ” κ΅λŒ€λ‘œ μž‘μ—…μ„ μ²˜λ¦¬ν•΄μ•Όλ λ•Œ μ‚¬μš©

 

 


πŸ‘Šν˜Όμžμ„œ ν•΄κ²°ν•˜κΈ°


1. μŠ€λ ˆλ“œ κ°œλ… 쒀더 μ‚΄νŽ΄λ³΄κΈ°

2. synchronized 말고 μ°Έκ³ ν• κ²Œ μžˆμ„κΉŒ?

 

 

λ°˜μ‘ν˜•