본문 바로가기

언어/Java

멀티 스레드

※ 스레드 : 프로세스를 구성하는 단위

운영체제는 실행 중인 프로그램을 프로세스(process)로 관리한다. 멀티 태스킹(multi tasking)은 두 가지 이상의 작업을 동시에 처리하는 것을 말하는데, 이때, 운영체제는 멀티 프로세스를 생성해서 처리한다. 하지만 멀티 태스킹이 꼭 멀티 프로세스를 뜻하지는 않는다.

하나의 프로세스 내에서 멀티 태스킹을 할 수 있도록 만들어진 프로그램도 있다. 예를 들어 메신저는 채팅 작업을 하면서 동시에 파일 전송 작업을 수행하기도 한다.

하나의 프로세스가 두 가지 이상의 작업을 처리할 수 있는 이유는 멀티 스레드(multi thread)가 있기 때문이다. 스레드(thread)는 코드의 실행 흐름을 말하는데 프로세스 내에 스레드가 두 개라면 두 개의 코드 실행 흐름이 생긴다는 의미이다. 멀티 프로세스는 서로 독립적이므로 하나의 프로세스에서 오류가 발생해도 다른 프로세스에게 영향을 미치지 않는다. 하지만 멀티 스레드는 프로세스 내부에서 생성되기 때문에 하나의 스레드가 예외를 발생시키면 프로세스가 종료되므로 다른 스레드에게 영향을 미친다.

 

프로세스 10개 < 한 프로세스에서 스레드 10개가 퍼포먼스가 빠르다
메인 스레드 혼자 일 = 싱글 스레드 애플리케이션
파생된 여러 스레드들이 일 = 멀티 스레드 애플리케이션

 

os가 cpu 점유율 정함
스레드 프로그램이 어려운 이유 : 어느 스레드가 언제 얼만큼 cpu를 점유할지 모름
멀티스레드환경에서는 메인스레드는 일이 끝나도 자기가 파생시킨 스레드가 안끝나면 그 스레드가 끝날때까지 기다림

메인스레드가 끝나야 프로세스가 종료됨.

Runnable 인터페이스

대표 메서드 +run():void // 스레드가 할 일을 기술한다

 

cf) uml표기법
+ public

- private

# protected
Thread 클래스 - Runnable 인터페이스의 하위클래스, 점선

 

대표 메서드 +start():void // 스레드를 시작시킨다

스레드 start 해야 실행된다.

스레드로부터 상속받는 하위클래스만들기

Caption 사용자정의 클래스, Runnable 인터페이스로부터 구현
+start():void // 사용자정의 클래스라 오버라이딩 되야함

sound 클래스 - Thread로부터 상속받는 하위클래스, 실선, 화살촉막기
대표 메서드 +run():void // 재정의

 

객체 생성한 후 스레드는 반드시 시작해야함. 시작하지 않으면 일반 객체일뿐
그래야 스레드가 Runnable 상태가 됨(cpu를 점유할 수 있는 대기상태)
메인스레드는 자동으로 만들어짐 RUN은 cpu를 점유한 상태
만약 사운드의 스레드0가 호출되면 Sound 객체의 오버라이드된 run() 메서드가 자동호출됨

우리는 객체생성에서 start 메서드만 호출하면 된다
CPU를 점유했다가 내쳐지면 종료가 되는게 아니라 Runnable 상태가 된다
라운드로빈(순서대로 처리되는 것) 방식으로 처리되는게 아니라 썼던 Thread가 또 채택될 수 있음
3개의 Thread가 줄서서 기다리다가 먼저 종료가 될지 아무도 모른다

처리 순서

※ main 스레드만 실행됨

class Sound extends Thread {
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" sound" + i );
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		//Thread ct = Thread.currentThread();
		//ct.getName();
		//위의 2줄을 아래 한줄로
//		Thread.currentThread().getName();
		System.out.println(Thread.currentThread().getName());	// 메인이라는 스레드 생성
		
		Sound s = new Sound();
		s.run();
		System.out.println("THE END");
	}
}

결과

※ 파생 스레드 하나 만듬
main이 무조건 먼저 cpu 점유하는 것은 아니다
Thread-0가 먼저 될 수도 있음

class Sound extends Thread {
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" sound" + i );
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName());	// 메인이라는 스레드 생성
		
		Sound s = new Sound();
//		s.run();
		s.start();	// 파생 스레드 하나 만듬
		System.out.println("THE END");
	}
}

결과

class Sound extends Thread {
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" sound" + i );
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName());	// 메인이라는 스레드 생성
		
		Sound s = new Sound();
		s.start();	// 파생 스레드 하나 만듬
		for(int i = 0; i < 100; i++) {
			System.out.println(" 동영상" + i );
			
		System.out.println("THE END");
		}
	}
}

간단한 제어만 할 수 있고 순서가 어떻게 될지 아무도 모름
캡션 스레드 만들기

//자막 100번 메인스레드에서 파생 Caption 자막
sound는 Thread에서 상속받으니까 부모가 제공하는 start 메소드상속받고있음
caption 클래스는 runnable 메소드 구현받으니 start 구현 못받음
caption 스레드로서 시작시키려면
Caption c = new Caption();

class Sound extends Thread {
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" sound" + i );
		}
	}
}

class Caption implements Runnable{
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" caption" + i );
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName());	// 메인이라는 스레드 생성
		
		Sound s = new Sound();
//		s.run();
		s.start();	// 파생 스레드 하나 만듬
		for(int i = 0; i < 100; i++) {
			System.out.println(" 동영상" + i );
		}
			
		Caption c = new Caption();;
//		c.start();
		Thread t = new Thread(c);
		t.start();
		
		System.out.println("THE END");
	}
}
class Sound extends Thread {
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" sound" + i );
		}
	}
}

class Caption implements Runnable{
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.print(Thread.currentThread().getName());
			System.out.println(" caption" + i );
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		//Thread ct = Thread.currentThread();
		//ct.getName();
		//위의 2줄을 아래 한줄로
//		Thread.currentThread().getName();
		System.out.println(Thread.currentThread().getName());	// 메인이라는 스레드 생성
		
		Sound s = new Sound();
//		s.run();
		s.start();	// 파생 스레드 하나 만듬
			
		/* 재사용성 높은 스레드일 경우 클래스이름을 만든다
		Caption c = new Caption();;
//		c.start();
		Thread t = new Thread(c);
		t.start();
		*/
		
		/*재사용성 없는 스레드일 경우 클래스이름을 만들지 않는다. 즉, 익명클래스로 객체생성을 한다.
		 * 
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 0; i < 100; i++) {
					System.out.print(Thread.currentThread().getName());
					System.out.println(" caption" + i );
				}
			}
		});
		t.start();
		*/
		// 위를 람다식으로 변경
		Thread t = new Thread(()->{
			for(int i = 0; i < 100; i++) {
				System.out.print(Thread.currentThread().getName());
				System.out.println(" caption" + i );
			}
		});
		t.start();

		for(int i = 0; i < 100; i++) {
			System.out.println(" 동영상" + i );
		}
		System.out.println("THE END");
	}
}

위에가 아래꺼
cpu를 뺏겨서 다른 cpu가 점유
run메서드 끝나면 종료

 

'언어 > Java' 카테고리의 다른 글

Thread pop, push  (0) 2023.08.16
ThreadSleep  (0) 2023.08.16
성능 향상 스트림  (0) 2023.08.15
기본자료형과 참조형의 차이  (0) 2023.08.10
Product 예제 4  (0) 2023.08.09