본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch14 스레드(thread)

728x90
반응형

1. 멀티 프로세스와 멀티 스레드

   ▷ 프로세스 : 운영체제는 실행 중인 프로그램을 관리

   ▷ 멀티 태스킹 : 두 가지 이상의 작업을 동시에 처리하는 것

   ▷ 스레드 : 코드의 실행 흐름

   ▷ 멀티 스레드 : 두 개의 코드 실행 흐름. 두 가지 이상의 작업을 처리

   ▷ 멀티 프로세스 : 프로그램 단위의 멀티 태스킹 / 멀티 스레드 : 프로그램 내부에서의 멀티 태스킹

 

 

2. 메인 스레드 

   ▷ 메인 스레드는 main() 메소드의 첫 코드부터 순차적으로 실행

   ▷ main() 메소드의 마지막 코드를 실행하거나 return 문을 만나면 실행 종료

   ▷ 메인 스레드는 추가 작업 스레드들을 만들어서 실행시킬 수 있음

   ▷ 메인 스레드가 작업 스레드보다 먼저 종료되더라도 작업 스레드가 계속 실행 중이라면 프로세스는 종료되지 않음.

 

 

3. 작업 스레드

   ▷ 작업 스레드 : 멀티 스레드 프로그램을 개발 시 먼저 몇 개의 작업을 병렬로 실행할지 결정하고 각 작업별로 스레드를 생성

 

◎ Thread 클래스로 직접 생성

   ▷ java.lang 패키지에 있는 Thread 클래스로부터 작업 스레드 객체를 직접 생성하려면 Runnable 구현 객체를 매개값으로 갖는 생성자를 호출

Thread thread = new Thread(Runnalbe target);

 

// Thread 클래스로 직접 생성

// 러너블 구현 객체를 매개값으로 같는 생성자 호출
Thread thread = new Thread(Runnable target);

// 러너블 인터페이스와 run 메소드 사용
class Task implements Runnable {
	@Override
    public void run() {
    // 스레드가 실행할 코드
    }
}

// 러너블 객체 생성
Runnable task = new Task();

// 스레드 객체 생성(러너블 객체를 매개값으로 사용)
Thread thread = new Thread(task);

// 익명으로 사용
Thread thread = new Thread(new Runnable() {
	@Override
    public void run() {
    // 스레드가 실행할 코드
    }
});

// 스레드 동작 실행
thread.start();

 

◎ Thread 클래스로 직접 생성 예시 1

import java.awt.Toolkit;

public class BeepPrintExample {
	public static void main(String[] args) {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i=0; i<5; i++) {
			toolkit.beep();
			try { Thread.sleep(500); } catch(Exception e) {}
		}
		
		for(int i=0; i<5; i++) {
			System.out.println("띵");
			try { Thread.sleep(500); } catch(Exception e) {}
		}
	}
}


▷  Toolkit 클래스의 beep 메소드를 사용하면 소리가 납니다.
▷  소리가 5번 울리면 '띵' 이라는 글자가 5번 나타납니다.

 

◎ Thread 클래스로 직접 생성 예시 2

import java.awt.Toolkit;

public class BeepPrintExample1 {
	public static void main(String[] args) {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				for(int i=0; i<5; i++) {
					toolkit.beep();
					try { Thread.sleep(500); } catch(Exception e) {}
				}				
			}
		});
		
		thread.start();
		
		for(int i=0; i<5; i++) {
			System.out.println("띵");
			try { Thread.sleep(500); } catch(Exception e) {}
		}
	}
}


▷  소리가 울릴때 마다 글자가 나타나는 것처럼 보입니다.(동작은 별개입니다.)

 

 

4.  Thread 이름

   ▷ Thread 클래스를 상속한 다음 run() 메소드를 재정의해서 스레드가 실행할 코드를 작성하고 객체를 생성

   ▷ 혹은 Thread 익명 자식 객체를 사용 가능

   ▷ 작업 스레드 이름을 thread-n 대신 다른 이름으로 설정하려면 Thread 클래스의 setName() 메소드 사용

   ▷ 어떤 스레드가 실행하고 있는지 확인 하려면 정적 메소드인 currentThread()로 스레드 객체의 참조를 얻습니다.

      → 이후 getName() 메소드로 이름을 출력합니다.

 

public class ThreadNameExample {
	public static void main(String[] args) {
		Thread mainThread = Thread.currentThread();
		System.out.println(mainThread.getName() + "실행");
		
		for(int i=0; i<3; i++) {
			Thread threadA = new Thread() {
				@Override
				public void run() {
					System.out.println(getName() + "실행");
				}
			};
			threadA.start();
		}
		
		Thread chatThread = new Thread() {
			@Override
			public void run() {
				System.out.println(getName() + "실행");
			}
		};
		chatThread.setName("chat-thread");
		chatThread.start();
	}
}

//	출력 :
//	main실행
//	Thread-0실행
//	Thread-1실행
//	chat-thread실행
//	Thread-2실행


▷  main이 가장 먼저 실행되고 나머지는 순서가 지속적으로 바뀌면서 실행됩니다.
▷  작업 스레드는 'Thread-n'이라는 이름을 자동적으로 가지고 있습니다.
▷  이름 변경하기 위해서는 setName을 사용하면 됩니다.

 

 

5. 스레드 상태

   ▷ 실행 대기 상태 : 실행을 기다리고 있는 상태

   ▷ 시행 상태 : CPU 스케줄링에 따라 CPU를 점유하고 run() 메소드를 실행.

      → 스케줄링에 의해 다시 실행 대기 상태로 돌아갔다가 다른 스레드가 실행 상태 반복

   ▷ 종료 상태 : 실탱 상태에서 run() 메소드가 종료되어 실행할 코드 없이 스레드의 실행을 멈춘 상태

 

◎ 일시 정지 상태

   ▷ 스레드가 실행할 수 없는 상태

   ▷ 스레드가 다시 실행 상태로 가기 위해서는 일시 정지 상태에서 실행 대기 상태로 가야함

   ▷ Thread 클래스의 sleep() 메소드 : 실행 중인 스레드를 일정 시간 멈추게 함

   ▷ 매개값 단위는 밀리세컨드(1/1000)

 

NO 구분 메소드 설명
1 일시 정지로 보냄 sleep(long millis) 주어진 시간동안 스레드를 일시 정지 상태로 만듭니다.
주어진 시간이 지나면 자동적으로 실행 대기 상태가 됩니다.
2 join() join() 메소드를 호출한 스레드는 일시 정지 상태가 됩니다.
실행 대기 상태가 되려면, join() 메소드를 가진 스레드가 종료되어야 합니다.
3 wait() 동기화 블록 내에서 스레드를 일시 정지 상태로 만듭니다.
4 일시 정지에서
벗어남
interrupt() 일시 정지 상태일 경우, InterruptedException을 발생시켜 실행 대기 상태 또는
종료 상태로 만듭니다.
5 notify()
notifyAll()
wait() 메소드로 인해 일시 정지 상태인 스레드를 실행 대기 상태로 만듭니다.
6 실행 대기로 보냄 yield() 실행 상태에서 다른 스레드에게 실행을 양보하고 실행 대기 상태가 됩니다.

 

◎ 일시 정지 예시

import java.awt.Toolkit;

public class SleepExample {

	public static void main(String[] args) {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		for(int i=0; i<10; i++) {
			toolkit.beep();
			try {
				Thread.sleep(3000);      
			} catch(InterruptedException e) {}
		}
	}
}


sleep을 이용해 3초 동안 main을 일시 정지 시킵니다.

 

◎ 일시 정지 예시 2

1. SumThread 클래스
public class SumThread extends Thread{
	private long sum;
	
	public long getSum() {
		return sum;
	}
	
	public void setSum(long Sum) {
		this.sum = sum;
	}
	
	@Override
	public void run() {
		for(int i=1; i<=100; i++) {
			sum+=i;
		}
	}
}​

 

2. JoinExample 메인 클래스
import java.awt.Toolkit;

public class JoinExample {

	public static void main(String[] args) {
		SumThread sumThread = new SumThread();
		sumThread.start();
		try {
			sumThread.join();
		} catch(InterruptedException e) {
		}
		
		System.out.println("1~100 합 : " + sumThread.getSum());
	}
}

//	출력 : 
//	1~100 합 : 5050​

▷ start만 하면 0이 출력되고 join을 통해 일시 정지하면 100까지의 합이 출력됩니다.

 

 

다른 스레드에게 실행 양보

   ▷ yield() 메소드 : 실행되는 스레드는 실행 대기 상태로 돌아가고, 다른 스레드가 실행되도록 양보합니다.

   ▷ 무의미한 반복을 막아 프로그램 성능을 향상시킵니다.

 

 

◎ 실행 양보 예제

1. WorkThread 클래스
public class WorkThread extends Thread {
	public boolean work = true;
	
	// 생성자
	public WorkThread(String name) {
		setName(name);
	}
	
	// 메소드
	public void run() {
		while(true) {
			if(work) {
				System.out.println(getName() + ": 작업처리");
			} else {
				Thread.yield();
			}
		}
	}
}​

 

2. YieldExample 메인 클래스
public class YieldExample {

	public static void main(String[] args) {
		WorkThread workThreadA = new WorkThread("workThreadA");
		WorkThread workThreadB = new WorkThread("workThreadB");
		
		workThreadA.start();
		workThreadB.start();
		
		try { Thread.sleep(5000); } catch (InterruptedException e) {}
		workThreadA.work = false;

		try { Thread.sleep(10000); } catch (InterruptedException e) {}
		workThreadA.work = true;
	}
}​


▷ A와 B가 번갈아 나오고 5초 뒤 B가 많이 나옵니다.
▷ 그 후 10초 뒤 A, B가 다시 번갈아가며 나옵니다.

 

스레드가 동작하는 것에 대해 코드로 구현해 보았습니다.

스레드는 순서대로 동작하는 것이 아니라 먼저 입력받는 것을 출력하는 것을 알았습니다.

 

다음 글에서 더 다뤄봅시다!!

 

단축키 팁!

control + shift + O : 필요한 import 자동 생성

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

 

728x90
반응형