2주차 12/07(수)

하이·2022년 12월 7일
0

수업

목록 보기
3/41
post-custom-banner

Thread

: 독립적인 실행 흐름

process

: 실행 중인 하나의 program(Excel, Powerpoint, browser, game)

이런 program이 실행되려면 OS로 부터 Resource(자원)를 할당받아서 실행

OS(Operating System) : 운영체제 / windows, ubountu, MacOS

Resource(자원)

  • code : 실행 명령어 코드
    data : 전역, 정적 변수(global, variable, static variable)
    Heap : 동적 할당 메모리 영역
    Stack : method, 함수를 호출했을 때 local variable(지역변수)를 위한 영역

=> Resource 4가지를 이용해서 실제로 작업을 수행하는 것을 Thread


  • 그럼 process 1개에 Thread가 1개만 존재하나요?
    : 1개만 있을 수도 있고 (Single-Thread process : 지금까지 작성한 Java program들 )
    : 여러개 있을 수도 있음 (Multi-Thread Process)


Java는 이런 Multi-Thread program 구현을 프로그램 언어차원에서 지원함

  • process 내에 thread의 갯수 제한은 없음
    => Thread마다 독립적인 Stack이 할당


Multi-Tasking & Multi-Processing

windows(OS)는 당연히 여러개의 process가 동시에 존재할 수 있다.
실제로 computer에서 일을 하는 주체는? CPU

(single core)
: core가 1개면 당연히 Multi processing(다중 처리)을 할 수 없음

=> 그러면 여러개의 프로그램을 동시에 실행할 수 있나요?
: Multi Tasking

: Time-slicing기법(시분할)을 이용해서 마치 동시에 진행되는 것처럼 동작시키는 기법



코어가 4개니까 동시에 작업할 수 있는 것도 4개

Core로 Thread를 실행할 때 core이 금날????? 경우가 발생



Thread의 장/단점

장점

: CPU와 Resource를 효율적으로 사용 가능
다중코어와 여러가지 메모리,코드 등을 공유해서 사용하기 때문에 효율이 좋음
: 사용자와의 응답성을 높일 수 있음
: 적은 메모리로 더 빠르게

단점

: 자원공유에 의한 동기화(Synchronization)문제를 해결하기 위해 잘못하면 교착상태(dead-lock)에 빠짐

* 교착상태

해결방안 : 교착상태 예방/회피/탐지/복구

Java에서 Thread를 만들려면 Thread class를 이용(=>우리가 제공받은 class)

방법

1. class MyClass extends Thread
: 이렇게 내가 정의한 Thread를 만들 수 있음
① 다중상속이 안 되기 때문에 제한이 생김
② 클래스의 결합도가 높아짐

2. interface를 이용하는 방법
: 조금 더 객체지향적 방법

코드로 알아보기

<JavaThread 프로젝트 생성>
ThreadEx_01.java
예제1)

package sampleproj;

class ThreadEx_01_01 extends Thread {
	
	// 새로운 독립적인 실행 흐름
	// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
	@Override
	public void run() {
		// 내가 실행하고 싶은 코드를 작성 !
		
	}	// 프로그램의 entry point
}

// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함

// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름

// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !

// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
	
	public static void main(String[] args) {
		// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
		int result = 10 / 0;
		
	}
	
}

package sampleproj;

class ThreadEx_01_1 extends Thread {
	
	public ThreadEx_01 () {
		
	}
	
	
	
	// 새로운 독립적인 실행 흐름
	// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
	@Override
	public void run() {
		// 내가 실행하고 싶은 코드를 작성 !
		
		// for문 같은 경우
		// 1. 집합자료구조를 이용하는 경우 => for~each구문
		// for(Stirng s : list) { }
		// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
		for(int i=0; i<5; i++) {
			System.out.println(this.getName());
		}//for()
		
	}	// 프로그램의 entry point
}

// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함

// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름

// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !

// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
	
	public static void main(String[] args) {
		// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
//		int result = 10 / 0;
		
		ThreadEx_01_1 t1= new ThreadEx_01_1();
		// t1은 Thread instance가 됨
		// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
		// 이 thread는 독립적인 실행 흐름을 가지고 있음
		// run()안에 그 내용을 기술하고 있음
		// 이제 이 thread를 실행시킬거에요
		t1.run();
		// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
		// Thread를 실행시킨 건 아님
		// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
		t1.start();	//run을 찾아가서 호출
		// start()를 이용해서 Thread를 실행시킴
		System.out.println("main thread 종료");
		
		
	}
	
}



package sampleproj;

class ThreadEx_01_1 extends Thread {
	
	public ThreadEx_01() {
		
	}
	
	
	
	// 새로운 독립적인 실행 흐름
	// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
	@Override
	public void run() {
		// 내가 실행하고 싶은 코드를 작성 !
		
		// for문 같은 경우
		// 1. 집합자료구조를 이용하는 경우 => for~each구문
		// for(Stirng s : list) { }
		// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
		for(int i=0; i<5; i++) {
			System.out.println(this.getName());
		}//for()
		
	}	// 프로그램의 entry point
}

// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함

// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름

// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !

// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
	
	public static void main(String[] args) {
		// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
//		int result = 10 / 0;
		
		ThreadEx_01_1 t1= new ThreadEx_01_1();
		// t1은 Thread instance가 됨
		// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
		// 이 thread는 독립적인 실행 흐름을 가지고 있음
		// run()안에 그 내용을 기술하고 있음
		// 이제 이 thread를 실행시킬거에요
		t1.run();
		// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
		// Thread를 실행시킨 건 아님
		// 거의 대부분의 method는 blocking method에요!
		// method 수행이 끝나고 return될 때까지 대기!
		// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
		t1.start();	//run을 찾아가서 호출
		// start()를 이용해서 Thread를 실행시킴
		System.out.println("main thread 종료");
		
		
	}
	
}

thread실행

t1.start()

-thread의 실행을 기다리지 않음
-> Thread Scheduler로 가서 언젠가는 실행



Thread의 상태 전이도 (기본)

예제2)

package sampleproj;


// 이렇게 만든 클래스는 당연히 Thread가 아님
// 단지, Runnable이라는 특별한 interface를 구현한 클래스일 뿐
// 그래서 getName() method를 이용하려면
//	현재 class를 찾아야함.
class ThreadEx_01_2 implements Runnable {
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0; i<5; i++) {
			System.out.println(Thread.currentThread().getName());	//Thread라는 class의 현재 동작 중인 Thread를 찾는다
		}//for()
		
	}	// 프로그램의 entry point
}
	



// 이 밑에 있는 클래스는 당연히 Thread이다. is-a 관계에 의한 !
class ThreadEx_01_1 extends Thread {
	
	public ThreadEx_01_1() {
		
	}
	
	
	
	// 새로운 독립적인 실행 흐름
	// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
	@Override
	public void run() {
		
		// for문 같은 경우
		// 1. 집합자료구조를 이용하는 경우 => for~each구문
		// for(Stirng s : list) { }
		// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
		for(int i=0; i<5; i++) {
			System.out.println(this.getName());	//getName은 Thread의 이름을 알아내는 객체
		}//for()
		
	}	// 프로그램의 entry point
}


		// 예전 설명
		// java TreadEx_01 => 실행하면..
		// JVM이 main method를 호출해서 프로그램을 시작함
		
		// Thread관점에서 다시 설명
		// java Thread_01 => 실행하면..
		// JVM이 내부적으로 Thread를 하나 생성
		// 이 Thread가 main method를 호출해서 실행
		// 이 Thread를 main thread라고 부름
		
		// process(프로그램)는 main method가 시작되면 시작하는 거고
		// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !
		
		// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
		// process가 종료됨
	public class ThreadEx_01 {
		
		
		public static void main(String[] args) {
			// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
//		int result = 10 / 0;
			
			Runnable r2 = new ThreadEx_01_2();	// Thread가 아님	
			Thread t2 = new Thread(r2);			// Thread가 됨 !
		
		ThreadEx_01_1 t1= new ThreadEx_01_1();
		// t1은 Thread instance가 됨
		// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
		// 이 thread는 독립적인 실행 흐름을 가지고 있음
		// run()안에 그 내용을 기술하고 있음
		// 이제 이 thread를 실행시킬거에요
//		t1.run();
		// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
		// Thread를 실행시킨 건 아님
		// 거의 대부분의 method는 blocking method에요!
		// method 수행이 끝나고 return될 때까지 대기!
		// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
		t1.start();	//run을 찾아가서 호출
		t2.start();
		// start();는 non-blocking.
		// start()를 이용해서 Thread를 실행시킴
		System.out.println("main thread 종료");
			
			
		}
		
	}
System.out.println(Thread.currentThread().getName());
//Thread라는 class의 현재 동작 중인 Thread를 찾는다



run할 때마다 순서가 달라짐


ThreadEx_02_1.java

package sampleproj;

//쉽게 Thread하기 위해 Thread class를 상속받음
class ThreadEx_02_1 extends Thread{
	public ThreadEx_02_1() {
		
	}
	
	public ThreadEx_02_1(String name) {
		super();
		this.setName(name);		// Thread 이름을 설정하는 method
		
		// Thread class의 생성자 중 문자열 하나를 받아들이는 생성자를 사용
		// 해당문자열로 Thread의 이름 설정
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0; i<5; i++) {
			System.out.println(this.getName());
		}//for()
	}	
}


public class ThreadEx_02 {

	public static void main(String[] args) {
		Thread t1 = new ThreadEx_02_1("My-Thread");		// thread를 만들어서

		t1.start();										// thread로 동작시켜 보아요
		
		System.out.println("main thread 종료!");
		
	}
	
	
	
}//



Stack의 변화

(Thread마다 Stack이 각각 할당됨)
start(); 라는 method

새로운 stack(t1 thread)k이 생김
start()를 호출하면 run() 호출
=>stack(main thread)에서 start() 사라짐



Single Core

적정량의 thread를 이용하면 다중처리할 때 속도가 굉장히 빨라짐



Thread의 특징, method

  1. runnable 상태의 thread(start()가 호출된)가 여러개 존재할 때 어떤 thread가 선택될 때는 Thread Scheduler가 처리

  2. Thread priority(우선순위)
    기본은 우선순위값이 5
    가장 높은 우선순위 : 10
    가장 낮은 우선순위 : 1

  • but, Multi core 환경에서는 priority가 영향을 주지 않으므로 신경 끄자

코드로 알아보기

ThreadEx_03.java

package sampleproj;


class ThreadEx_03_1 extends Thread{
	
	public ThreadEx_03_1() {


	}
	
	public ThreadEx_03_1(String name) {
		super(name);

	}
	
		
	
	@Override
	public void run() {
	
	}
}//


public class ThreadEx_03 {

	public static void main(String[] args) {
		
		Thread t1 = new ThreadEx_03_1("Thread-01");
		Thread t2 = new ThreadEx_03_1("Thread-02");
		
		// 실행시키기 전에 우선순위를 매겨보자
		t1.setPriority(1);
		t2.setPriority(9);
		
		t1.start();
		t2.start();
	}
	
}//


DaeMon Thread(데몬 쓰레드)

  • 하나의 Thread를 보조하는 역할의 thread를 지칭
  • 일반 Thread가 종료되면 Daemon Thread가 자동 종료
  • ex) word/excel/hwp

코드로 알아보기

ThreadEx_04.java

package sampleproj;

public class ThreadEx_04 implements Runnable{
	
	//field
	static boolean autoSave = false;
	
	public static void main(String[] args) {
		
		Thread t = new Thread(new ThreadEx_04());
		t.setDaemon(true);		//자신을 만든 thread(Main)의 보조 thread가 됨
		
		t.start();
		
		for(int i=0; i<10; i++) {
			try {
				Thread.sleep(1000);		
			} catch(InterruptedException e) {
			}
			if( i == 5) {
				autoSave = true;
				
			}//try() end
			
		}//for() end
		
	}

	@Override
	public void run() {
		
		while(true) {
			// Thread를 일정시간동안 재울 거에요
			try {
				Thread.sleep(3000);				//밀리세컨즈 단위 => 3초, class 이름으로 sleep method 바로 호출 => static
												//일정 시간동안 thread를 재웠다가,
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
			if(autoSave) {
				System.out.println("자동저장 되었어요!");
			}
			
		}//while() end
		
	}
	
}//

Thread.sleep(1000); //현재 Thread를 재움

	t.setDaemon(true);		//자신을 만든 thread(Main)의 보조 thread가 됨

이 부분 주석 걸면 무한루프됨



Thread의 method

: method를 이용해서 thread의 상태가 전이됨

① sleep()

: 지정된 시간만큼 Thread를 재운다
: try~catch를 이용해 Exception Handling을 해줘야 한다 (강제)



코드로 알아보기

ThreadEx_05.java

package sampleproj;


class ThreadEx_05_1 extends Thread {
	@Override
	public void run() {
		for(int i=0; i<300; i++) {
		System.out.println("-");
		}
		System.out.println("<< Thread 1 종료 >>");
	}
}

class ThreadEx_05_2 extends Thread {
	@Override
	public void run() {
		for(int i=0; i<300; i++) {
			System.out.println("|");
		}
		System.out.println("<< Thread 2 종료 >>");
	}
}


public class ThreadEx_05 {

	public static void main(String[] args) {
		Thread t1 = new ThreadEx_05_1();
		Thread t2 = new ThreadEx_05_2();
		
		t1.start();
		t2.start();
		
		try {
			t1.sleep(2000);		// Thread.sleep(2000)
		} catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("<<main thread 종료>>");
		
		
	}
	
}//



package sampleproj;


class ThreadEx_05_1 extends Thread {
	@Override
	public void run() {
		
		try {
			Thread.sleep(3000);
		}catch(InterruptedException e){
			System.out.println("소리없는 아우성!");
		}
		
		for(int i=0; i<300; i++) {
			System.out.println("-");
		}
		System.out.println("<< Thread 1 종료 >>");
	}
}

class ThreadEx_05_2 extends Thread {
	@Override
	public void run() {
		for(int i=0; i<300; i++) {
			System.out.println("|");
		}
		System.out.println("<< Thread 2 종료 >>");
	}
}


public class ThreadEx_05 {

	public static void main(String[] args) {
		Thread t1 = new ThreadEx_05_1();
		Thread t2 = new ThreadEx_05_2();
		
		t1.start();
		t2.start();

		System.out.println("<<main thread 종료>>");
		
		
	}
	
}//

sleep이 누워있는 이유 : static이기 때문

static의 가장 큰 특징

: instance없이 사용할 수 있다
: field, method 앞에 붙을 수 있다
: class명을 이용해서 사용
: instance를 이용해서도 사용할 수 있다

instance/class . field/method()

profile
기록의 즐거움 😆💻
post-custom-banner

0개의 댓글