IT/development

[Java] μžλ°” Thread(feat. Thread , Runnable, join)

μ•Œ 수 μ—†λŠ” μ‚¬μš©μž 2022. 11. 23.

image source:https://unsplash.com/s/photos/java

 

Java Thread 😏

image source:https://unsplash.com/s/photos/thread

μŠ€λ ˆλ“œλž€ ν•˜λ‚˜μ˜ ν”„λ‘œμ„ΈμŠ€ μ•ˆμ—μ„œ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜λŠ” μž‘μ—… λ‹¨μœ„λ₯Ό λœ»ν•¨

λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€μ—λŠ” ν•œ 개 μ΄μƒμ˜ μŠ€λ ˆλ“œκ°€ μ‘΄μž¬ν•˜λ©° μž‘μ—…μ„ μˆ˜ν–‰ν•¨

λ‘κ°œ μ΄μƒμ˜ μŠ€λ ˆλ“œλ₯Ό κ°€μ§€λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό λ©€ν‹°μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€λΌκ³  함

β€» ν”„λ‘œμ„ΈμŠ€ : 싀행쀑인 ν”„λ‘œκ·Έλž¨, μš΄μ˜μ²΄μ œμ— μ˜ν•΄ λ©”λͺ¨λ¦¬ 곡간을 ν• λ‹Ή λ°›μ•„ λ™μž‘μ€‘μΈ 것을 λœ»ν•¨

이런 ν”„λ‘œμ„ΈμŠ€λŠ” ν”„λ‘œκ·Έλž¨μ— μ‚¬μš©λ˜λŠ” 데이터, λ©”λͺ¨λ¦¬ λ“±μ˜ μžμ›, μŠ€λ ˆλ“œλ‘œ ꡬ성됨

 

 

Thread의 생성주기 😊

Runnable μƒνƒœ : 

μŠ€λ ˆλ“œ μ‹€ν–‰ μ „ μ€€λΉ„μƒνƒœ

Running μƒνƒœ :

μŠ€μΌ€μ€„λŸ¬μ— μ˜ν•΄ μ„ νƒλœ μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λŠ” 단계

Blocked μƒνƒœ : 

μŠ€λ ˆλ“œκ°€ μž‘업을 μ™„μˆ˜ν•˜μ§€ λͺ»ν•˜κ³  μž μ‹œ μž‘업을 λ©ˆμΆ”λŠ” λ‹¨κ³„

 

 

Thread의 생λͺ…μ£ΌκΈ° 😢

Runnable (μ€€λΉ„μƒνƒœ)

μŠ€λ ˆλ“œ μ‹€ν–‰λ˜κΈ° μœ„ν•œ μ€€λΉ„단계, CPU λ―Έμ μœ  μ€‘이고 μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ λŒ€κΈ°ν•˜κ³  μžˆλŠ” μƒνƒœ

 

Running (μ‹€ν–‰μƒνƒœ)

CPU μ μœ ν•˜μ—¬ μ‹€ν–‰ μ€‘인 μƒνƒœμ΄κ³  run() λ©”μ„œλ“œλŠ” JVM만이 ν˜ΈμΆœ κ°€λŠ₯
μ€€λΉ„μƒνƒœμ˜ μ—¬λŸ¬ μŠ€λ ˆλ“œ μ€‘ μš°μ„  μˆœμœ„ μŠ€λ ˆλ“œ κ²°μ • λ  μ‹œ JVM이 μžλ™μœΌλ‘œ run() λ©”μ„œλ“œ ν˜ΈμΆœ -> μŠ€λ ˆλ“œκ°€ Running μƒνƒœλ‘œ μ§„μž…

 

Dead (μ’…λ£Œμƒνƒœ)

μ‹€ν–‰μƒνƒœμ—μ„œ μŠ€λ ˆλ“œκ°€ λͺ¨λ‘ μ‹€ν–‰λ˜κ³  λ‚œ ν›„ μ™„λ£Œ μƒνƒœ(doneμƒνƒœλΌκ³ λ„ ν•¨)

 

Blocked (μ§€μ—° μƒνƒœ)

CPU μ μœ κΆŒμ„ μƒμ‹€ν•œ μƒνƒœ, ν›„에 νŠΉμ • λ©”μ„œλ“œ μ‹€ν–‰ μ‹œμΌœ μ€€λΉ„μƒνƒœλ‘œ μ „ν™˜,
wait() λ©”μ„œλ“œμ— μ˜ν•΄ Blocked μƒνƒœκ°€ λœ μŠ€λ ˆλ“œλŠ” nofity() λ©”μ„œλ“œ ν˜ΈμΆœ λ  μ‹œ μ€€λΉ„μƒνƒœλ‘œ κ°, 
sleep(μ‹œκ°„) λ©”μ„œλ“œμ— μ˜ν•΄ Blocked μƒνƒœκ°€ λœ μŠ€λ ˆλ“œλŠ” μ§€μ •λœ μ‹œκ°„이 μ§€λ‚˜λ©΄ μ€€λΉ„ μƒνƒœλ‘œ κ°

 

 

Thread 생성/μ‹€ν–‰ πŸ˜—

μŠ€λ ˆλ“œ 생성/μ‹€ν–‰ 방법은 2κ°€μ§€κ°€ 있음

λ‘˜ λ‹€ run() λ©”μ†Œλ“œμ— μž‘μ—…ν•  λ‚΄μš©μ„ μž‘μ„±ν•˜λ©΄ λœλ‹€.

new Thread()둜 객체 생성 ν›„ start() μ‹€ν–‰ μ‹œ λ‚΄κ°€ μž‘μ„±ν•œ run()에 μž‘μ„±λœ λ‚΄μš©μ΄ μ‹€ν–‰λœλ‹€.

 

1.Thread class 상속

μŠ€λ ˆλ“œ 클래슀λ₯Ό 상속 받을 경우 λ‹€λ₯Έ 클래슀λ₯Ό 상속 λ°›μ§€ λͺ»ν•˜κΈ°μ— 일반적으둜 Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법을 많이 μ‚¬μš©ν•¨

// Thread class 직접 상속 예제
package java_test.dev.java;

public class Thread1 extends Thread {
	private int[] cnt;

	public Thread1(String threadname) {
		super(threadname);
		cnt = new int[10];

		for (int start = 0; start < cnt.length; start++) {
			cnt[start] = start;
		}
	}
	// μŠ€λ ˆλ“œ μž‘μ—… λ‚΄μš©
	public void run() {
		for (int start : cnt) {
			try {
				// 1초 λŒ€κΈ°
				Thread.sleep(1000);
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}

			System.out.println("μŠ€λ ˆλ“œμ΄λ¦„:" + currentThread().getName());
			System.out.println("temp value :" + start);
		}
	}
	// 메인 호좜
	public static void main(String[] args) {
		Thread1 t1 = new Thread1("첫번째");
		t1.start();
	}
}

 

 

2.Runnable μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„

좔상 λ©”μ„œλ“œμΈ run() 1개만 κ°€μ§€κ³  μžˆλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

// Runnable μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„ 예제
package java_test.dev.java;

public class Thread2 implements Runnable {
	private int[] temp;

	public Thread2() {
		temp = new int[10];

		for (int start = 0; start < temp.length; start++) {
			temp[start] = start;
		}
	}
	// μŠ€λ ˆλ“œ μž‘μ—… λ‚΄μš©(Runnable κ΅¬ν˜„ μ‹œ κ°•μ œ μ˜€λ²„λΌμ΄λ“œ)
	@Override
	public void run() {
		for (int start : temp) {
			try {
				// 1초 λŒ€κΈ°
				Thread.sleep(1000);
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
			System.out.println("μŠ€λ ˆλ“œμ΄λ¦„:" + Thread.currentThread().getName());
			System.out.println("temp value :" + start);
		}
	}
	public static void main(String[] args) {
		Thread2 t2 = new Thread2();
		Thread t = new Thread(t2, "λ‘λ²ˆ μ§Έ");
		t.start();
	}
}

 

 

λ©€ν‹° μŠ€λ ˆλ“œ

μ—¬λŸ¬ μŠ€λ ˆλ“œλ₯Ό λ™μ‹œμ— μ‹€ν–‰μ‹œν‚€λŠ” 기법

// λ©€ν‹° μŠ€λ ˆλ“œ 예제
package java_test.dev.java;

class ATM implements Runnable {
    private long depositeMoney = 10000;
    
    // μŠ€λ ˆλ“œμ—μ„œ ν•  μž‘μ—…
    public void run() {
    // multi threadμ—μ„œ 데이터 곡유
	synchronized (this) {
			
	    for (int i = 0; i < 10; i++) {
	    		// μ€€λΉ„μƒνƒœλ‘œ 변함
	           notify();
		try {
			// wait()으둜 인해 blocked μƒνƒœλ‘œ 변함
			wait();
			// 1초 λŒ€κΈ°
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// μž”μ•‘μ΄ μ—†μ–΄μ§€λ©΄ 반볡문 λΉ μ Έλ‚˜μ˜΄
		if (getDepositeMoney() <= 0)
			break;
		withDraw(1000);
	    }
	}
}
// 1000원씩 차감
public void withDraw(long howMuch) {
	// μž”μ•‘μ΄ 있으면
	if (getDepositeMoney() > 0) {
		depositeMoney -= howMuch;
		System.out.print(Thread.currentThread().getName() + " , ");
		System.out.printf("μž”μ•‘ : %,d 원 %n", getDepositeMoney());
	} else {
		System.out.print(Thread.currentThread().getName() + " , ");
		System.out.println("μž”μ•‘μ΄ λΆ€μ‘±ν•©λ‹ˆλ‹€.");
	}
}
// μž”μ•‘ 쑰회
public long getDepositeMoney() {
	return depositeMoney;
    }
}

public class MultiThread {
	// main μ‹€ν–‰
    public static void main(String[] args) {
	ATM atm = new ATM();
	// multi thread 생성
	Thread mother = new Thread(atm, "mother");
	Thread son = new Thread(atm, "son");
	// multi thread μ‹€ν–‰
	mother.start();
	son.start();
    }
}

 

synchronized λ•Œλ¬Έμ— 2개의 μŠ€λ ˆλ“œμ—μ„œ 10,000원이 같이 μ‚¬μš©λœ κ±Έ 확인할 수 있음

 

Join(μŠ€λ ˆλ“œ λŒ€κΈ°)

μŠ€λ ˆλ“œλŠ” 보톡 λ‹€λ₯Έ μŠ€λ ˆλ“œμ™€ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜μ§€λ§Œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Ό λ˜λŠ” κ²½μš°κ°€ λ°œμƒν•  수 있음

ex) AμŠ€λ ˆλ“œκ°€ μ’…λ£Œλœ ν›„ B μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜μ–΄μ•Ό 될 경우

이 λ•Œ join() μ‚¬μš©

package java_test.dev.java;

class ThreadJoin implements Runnable{

	@Override
	// μŠ€λ ˆλ“œ κ΅¬ν˜„
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("μ“°λ ˆλ“œ1단계");
		thread2();
	}
	
	public void thread2() {
		System.out.println("μ“°λ ˆλ“œ2단계");
		thread3();
	}

	public void thread3() {
		System.out.println("μ“°λ ˆλ“œ3단계");
	}
	
	public static void main(String[] args) {
		// main thread μ‹œμž‘ λ©”μ‹œμ§€ 좜λ ₯
		System.out.println(Thread.currentThread().getName() + " start");
		Runnable r = new ThreadJoin();
		Thread thread = new Thread(r);
		// μŠ€λ ˆλ“œ μ‹€ν–‰
		thread.start();
		// main thread μ’…λ£Œ λ©”μ‹œμ§€ 좜λ ₯ 
		System.out.println(Thread.currentThread().getName() + " end");
		System.out.println("===========================================================");
	}
}

 

μœ„ κ²°κ³Όλ₯Ό 보면 main threadκ°€ μ’…λ£Œλ˜κ³ λ„ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λŠ” κ±Έ μ•Œ 수 μžˆλ‹€.

이λ₯Ό μŠ€λ ˆλ“œκ°€ μ’…λ£Œλœ ν›„ 메인을 μ’…λ£Œμ‹œν‚€λ„λ‘ λ³€κ²½ν•˜λ €λ©΄ μ•„λž˜μ²˜λŸΌ λ³€κ²½ν•˜λ©΄ λœλ‹€.

 

public static void main(String[] args) {
		// main thread μ‹œμž‘ λ©”μ‹œμ§€ 좜λ ₯
		System.out.println(Thread.currentThread().getName() + " start");
		Runnable r = new ThreadJoin();
		Thread thread = new Thread(r);
		// μŠ€λ ˆλ“œ μ‹€ν–‰
		thread.start();
        
		// thread.join() μΆ”κ°€(μ˜ˆμ™Έμ²˜λ¦¬ ν•„μˆ˜)
		try {
			// thread μ’…λ£ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
			thread.join();
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		// main thread μ’…λ£Œ λ©”μ‹œμ§€ 좜λ ₯ 
		System.out.println(Thread.currentThread().getName() + " end");
		System.out.println("===========================================================");
	}

 

메인 μ‹œμž‘ ν›„ μŠ€λ ˆλ“œ μ’…λ£Œ ν›„ 메인이 μ’…λ£Œλœ κ±Έ λ³Ό 수 μžˆλ‹€.

 

μ°Έμ‘° : μ½”λ”©νŒ©ν† λ¦¬λ‹˜ λΈ”λ‘œκ·Έ, 2018.12.17, https://coding-factory.tistory.com/279,

          TCP School, http://www.tcpschool.com/java/java_thread_concept

            μ½”λ”©λ²Œλ ˆλ‹˜ λΈ”λ‘œκ·Έ, https://dpdpwl.tistory.com/13

λŒ“κΈ€