java/java.lang

[java/lang] 7. Thread 클래스

jeri 2024. 6. 16. 23:54
반응형

01. 스레드(Thread)의 개념

  • 프로그램에서 명령을 실행하기 위한 최소의 작업 단위 - 프로그램 흐름
  • 하나의 스레드 = 하나의 코드 실행 흐름
  • 프로세스(Process) : 메모리에 저장되어 중앙처리장치(CPU)에 의해 실행되는 명령 프로그램
  • [1개 프로세스 내 2개 스레드가 있다] = 2개의 코드 실행 흐름을 가진 프로그램

🎩단일 스레드 프로그램

  • JVM에 의해 생성된 main 스레드를 이용하여 main() 메소드의 명령 실행
  • main 메소드가 종료되면 main 스레드는 자동 소멸 - 프로그램 종료

🎩다중 스레드 프로그램

  • 프로그램 개발자가 스레드를 직접 생성하여 여러 명령을 동시에 실행되도록 만든 프로그램
  • 프로그램의 모든 스레드가 소멸되면 프로그램 종료
  • 즉, 메인스레드가 끝난다고 해서 프로그램이 종료되지는 않음
  • ex. GUI프로그램, Web프로그램 등은 다중 스레드 프로그램으로 작성

02. Thread클래스

  • 스레드 관련 정보를 저장하고 스레드 관련 기능을 메소드로 제공하는 클래스
  • 중요한 것은 스레드객체를 제어하는 것보다 스레드를 만드는 것이 더 중요하다!!!!

🎩다중스레드를 사용해야 하는 이유

  • CPU가 여러개 있지 않은 이상 명령은 동시 처리 불가능
  • PC에 CPU는 한개
  • 그래서 스레드를 여러개 만드는 것
  • 스레드 하나가 아닌 여러개 있다면 명령이 동시에 처리하는 것처럼 보임
  • 대다수의 프로그램은 스레드 여러개로 만듦
  • 콘솔프로그램은 단일 스레드 가능
  • GUI프로그램은 무조건 다중 스레드..
    • 메인 스레드 말고(JVM이 만들어준) , 우리가 직접 스레드를 만들어 사용해야함
    • 왜? 명령들이 동시에 처리될 수 있도록 하기 위해!!!

 

 

 

 

03. 단일스레드 프로그램

  • JVM에 의해 생성된 main 스레드를 이용하여 main() 메소드의 명령 실행
  • main 메소드가 종료되면 main 스레드는 자동 소멸 - 프로그램 종료

1. 🎩SingleThreadApp 프로그램

package xyz.itwill.thread;

//스레드(Thread) : 프로그램(프로세스)에서 명령을 실행하기 위한 최소의 작업 단위 - 프로그램 흐름
//프로세스(Process) : 메모리에 저장되어 중앙처리장치(CPU)에 의해 실행되는 명령 

//단일 스레드 프로그램
// => JVM에 의해 생성된 main 스레드를 이용하여 main() 메소드의 명령 실행
// => main() 메소드가 종료되면 main 스레드는 자동 소멸 - 프로그램 종료
public class SingleThreadApp {


	//메인메소드
	public static void main(String[] args) {

		/*
		System.out.println("SingleThreadApp 클래스의 main() 메소드 시작");

		//Thread 클래스 : 스레드 관련 정보를 저장하고 스레드 관련 기능을 메소드로 제공하는 클래스
		//Thread.currentThread() : 현재 사용중인 스레드에 대한 Thread 객체를 반환하는 메소드
		//Thread.getName() : Thread 객체에 저장된 스레드의 이름(식별자)을 반환하는 메소드 
		System.out.println("["+Thread.currentThread().getName()"] 스레드에 의해 main() 메소드의 명령 실행");
		
		//🍯 메소드를 한번만 호출한다면? 참조변수 생성해 객체를 저장하지 않는다

		//객체를 사용하여 메소드를 호출한 경우 스레드가 클래스의 메소드로 이동하여 명령 실행
		// => 메소드의 명령을 모두 실행한 뒤 다시 되돌아와 나머지 명령 실행
		new SingleThread().display();//객체를 생성한 후 메소드 호출
		
		
		System.out.println("SingleThreadApp 클래스의 main() 메소드 종료");
		*/
		

//SingleThreadApp 클래스의 main() 메소드 시작
//[main] 스레드에 의해 main() 메소드의 명령 실행
//SingleThread 클래스의 display() 메소드 시작
//[main] 스레드에 의해 display() 메소드의 명령 실행
//SingleThread 클래스의 display() 메소드 종료
//SingleThreadApp 클래스의 main() 메소드 종료


		new SingleThread().display();
		
		for(char i='0';i<='9';i++) {
			System.out.print(i);
		}
//ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

	}
}

2. 🎩SingleThread 클래스

package xyz.itwill.thread;

public class SingleThread {
	public void display() {
		/*
		System.out.println("SingleThread 클래스의 display() 메소드 시작");
		
		//Thread.currentThread.getName() : 현재 사용중인 스레드에 대한 Thread 객체에 저장된 스레드의 이름(식별자)을 반환
		System.out.println("["+Thread.currentThread().getName()"] 스레드에 의해 display() 메소드의 명령 실행");
		
		System.out.println("SingleThread 클래스의 display() 메소드 종료");
		*/
		
		for(char i='A';i<='Z';i++) {
			System.out.print(i);
		}
	}
}

 

 

 

 

04. 다중스레드 프로그램

  • 프로그램 개발자가 스레드를 직접 생성하여 여러 명령을 동시에 실행되도록 만든 프로그램
  • 메인스레드가 끝나도 프로그램이 종료되지 않음
  • 프로그램의 모든 스레드가 소멸되어야 프로그램 종료
  • 즉, 메인스레드가 끝난다고 해서 프로그램이 종료되지는 않음
  • ex. GUI프로그램, Web프로그램 등은 다중 스레드 프로그램으로 작성

1. 🎩MultiThreadApp 프로그램

  • 다중 스레드로 프로그램(main, 스레드1,2,3)

package xyz.itwill.thread;

//🎩다중 스레드 프로그램
// => 프로그램 개발자가 스레드를 직접 생성하여 여러 명령을 동시에 실행되도록 만든 프로그램
// => 프로그램의 모든 스레드가 소멸되면 프로그램 종료
// => GUI 프로그램, Web 프로그램 등은 다중 스레드 프로그램으로 작성

//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-1
//step1.
// => Thread 클래스를 상속받은 자식클래스 작성
//step2.
// => Thread 클래스를 상속받은 자식클래스에 run() 메소드를 오버라이드 선언 
// => run() 메소드에는 프로그램 개발자에 의해 생성된 스레드가 실행할 명령 작성
//step3.
// => Thread 클래스를 상속받은 자식클래스로 객체 생성 - Thread 객체 생성
// => 자식클래스로 객체를 생성하면 부모객체인 Thread객체가 먼저 생성된다
//step4.
// => 자식클래스의 객체로 start() 메소드 호출 - Thread 객체의 start() 메소드 호출
// => Thread 객체로 새로운 스레드를 만들어 자식클래스에 오버라이드 선언된 run() 메소드의 명령 실행
// => 실제 Thread 객체의 start 메소드가 호출됨 (부모객체 간접 호출)

//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-2
//step1.
// => Runnable 인터페이스를 상속받은 자식클래스 작성
// => 자식클래스가 다른 클래스를 상속받아 Thread 클래스를 상속받지 못할 경우 사용하는 방법
//step2.
// => Runnable 인터페이스를 상속받은 자식클래스에 run() 메소드를 오버라이드 선언
// => run() 메소드에는 프로그램 개발자에 의해 생성된 스레드가 실행할 명령 작성
//step3.
// => 생성자 매개변수에 Runnable 인터페이스를 상속받은 자식클래스의 객체를 전달받아 생성 - Thread 객체 생성
//step4.
// => Thread 객체로 start() 메소드 호출 - Thread 객체의 start() 메소드 호출
// => Thread 객체로 새로운 스레드를 만들어 Runnable 인터페이스를 상속받은 자식클래스의 오버라이드 선언된 run() 메소드에 명령 실행

public class MultiThreadApp {

	//main() 메소드에 의해 전달되는 모든 예외는 JVM에 의해 자동으로 예외 처리
	public static void main(String[] args) throws InterruptedException {
		//JVM에 의해 main 스레드가 생성되어 main() 메소드의 명령 실행 - JVM은 main() 메소드의 명령만!!! 실행
		
		//스레드의 존재가치없는 생성방법
		/*	
		//Thread 객체를 생성하여 start() 메소드 호출
		// => 새로운 스레드가 만들어지고 Thread 클래스의 run() 메소드를 호출하여 명령 실행
		// => Thread 클래스의 run() 메소드에는 명령 미존재
		//=> 즉, 스레드가 생성은 되지만, 문제는 실행할 명령이 없어서 스레드 생성해도 아무런 의미가 없음
		Thread thread=new Thread();
		thread.start();
		*/
		
		//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-1
		/*
		//방법1. 💚객체 생성해 참조변수에 저장
		MultiThreadOne one=new MultiThreadOne();
		//Thread.start() : Thread 객체로 새로운 스레드를 생성하여 run() 메소드를 호출하여 실행하는 메소드
		one.start(); //스레드1
		//Thread 객체는 start() 메소드로 하나의 스레드만 생성하여 명령 실행 가능 - Thread 객체로 start() 메소드를 여러번 호출할 경우 IllegalThreadStateException 발생
		// => 다중 스레드 프로그램에서 예외가 발생된 경우 예외가 발생된 스레드만 자동 소멸
		//one.start(); //스레드1과 동일한 스레드 호출명령이기 때문에 error
		*/

		 // => Thread클래스의 다양한 메소드들이 있지만, 그 중 start()메소드 한번만 호출할 것이기 때문에 객체를 생성 후 바로 메소드 호출해보자!
		 // => Thread.stop()메소드는 Deprecated(비권장) - 직접소멸하면 원치않는 스레드까지 소멸될 수 있기 때문

		//방법2. 💚객체만 생성하고 참조변수에 저장은 안함
		//Thread 객체로 start() 메소드외 다른 메소드를 호출하지 않을 경우 참조변수를 사용하지 않고 객체를 생성하여 직접 start() 메소드 호출하는 것을 권장
		// => 새로운 스레드가 생성되어 MultiThreadOne 클래스의 run() 메소드의 명령 실행
		new MultiThreadOne().start();	//🎩스레드1
		new MultiThreadOne().start();	//🎩스레드2

		//주의)
		//아래와 같은 메소드호출은 main메소드의 스레드로 명령 실행됨, 반드시 start()메소드를 사용해야 다른 스레드가 호출됨
		//new MultiThreadOne().run();  //main메소드의 스레드로 run()메소드실행

		//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-2
		// => 방법1. 이용해 새로운 스레드 생성
		//Thread(Runnable target) : Runnable 인터페이스를 상속받은 자식클래스의 객체를 전달 받아 Thread 객체를 생성하는 생성자
		// => Thread 객체의 run() 메소드를 오버라이드 선언하는 것과 같은 효과 
		new Thread(new MultiThreadTwo()).start(); //🎩스레드3
		
		for(char i='0';i<='9';i++) {
			System.out.print(i);
			
			//Thread.sleep(long ms) : 현재 명령을 실행하는 스레드를 원하는 시간(ms)만큼 일시적으로 중지하는 메소드 
			// => InterruptedException 발생 : 일반 예외 - 예외처리를 하지 않으면 에러 발생
			// => try-catch(예외처리)보다 main메소드에게 떠넘기면 JVM이 알아서 예외처리해줌(예외전달)
			Thread.sleep(500);			
		}
	}
}

2. 🎩MultiThreadOne 클래스

package xyz.itwill.thread;

//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-1
public class MultiThreadOne extends Thread {
	@Override
	public void run() {
		for(char i='A';i<='Z';i++) {
			System.out.print(i);
			try { //오버라이드 선언된 메소드 안 명령은 무조건 try-catch만 가능
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

3. 🎩MultiThreadTwo 클래스

package xyz.itwill.thread;

//🎩프로그램 개발자가 새로운 스레드를 생성하여 명령을 실행하는 방법-2
public class MultiThreadTwo implements Runnable {
	@Override
	public void run() {
		for(char i='a';i<='z';i++) {
			System.out.print(i);
			try { //오버라이드 선언된 메소드 안 명령은 무조건 try-catch만 가능
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
반응형