2주차 12/08(목)

하이·2022년 12월 8일
0

수업

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

복습

process

: 실행 중인 program
: 프로그램이 실행되려면 OS로부터 resource(자원)

Resouce : code, Data, Heap, Stack

JAVA 작동방식

java 프로그램에서 code를 작성한다 = ~.java
Javac.complier를 이용해서 compile을 함 => bytecode 생김 (~.class file)
-> Java interpreter 실행
-> JVM(얘도 프로세스 = 여러 thread가 숨어 있음 ex)garbage collector가 지켜보다가 발견하면 청소함)
-> JVM이 내부에 내 프로그램을 수행시키기 위한 별도의 Thread 생성 = main thread
-> main thread 는 main() method 호출

Thread

Java에서 Thread 생성 -> 실행 -> 어떤 code를 수행함 ( run() method 안에 있어야함)

방법
1. Thread class 상속

class A extends Thread {
	@Override
	run(){
	}
}

=>

A a = new A();
a.start()	//Thread를 실행가능한 형태인 Runnable 상태로 전환

2. Runnable interface를 구현한 객체를 이용

class A implements Runnable {
	@Override
    run(){
    }
}

=>

A r= new A();				// Runnable r = new A(); 도 가능. is-a 관계에 의해
Thread a = new Thread(r)	// r에 run 메소드를 가지고 있는 인자를 넣음)
a.start();

Thread를 배우기 전

=> main thread 1개만 이용

  • single thread
    : 실행 흐름이 1개이기 때문에 순차처리
    => 처리가 안 되는 경우가 많고
    => 처리가 되더라도 효율성이 너무 낮음

  • multi thread
    : 다중thread를 이용해서 해결

Thread의 상태 전이도

new - start()



Thread를 제어하는 method

sleep

: static method
: 특정 지정 못함. 현재 !

start() : 시작 method
suspend() : 일시정지 method
resume() : 다시 실행 method(일시정지된 후)
stop() : 종료 method

dead-lock 자주 발생하여 deprecated 되기 때문에 쓰면 안 됨

그러면 어떤 method를 이용하나요? 아래와 같은 로직으로 처리함

  • interrupt()
  • interrupted()
  • isInterrupted()

코드로 알아보기

ThreadEx_06.java

package sampleproj;

import javax.swing.JOptionPane;

class ThreadEx_06_1 extends Thread {
	
	@Override
	public void run() {
		
		int i = 10;									// 지역변수
		
		while(i != 0) {
			System.out.println(i--);				// 10출력 후 i값을 1감소	
		}
		System.out.println("카운트가 종료되었습니다.");
		
	}
}

public class ThreadEx_06 {

	public static void main(String[] args) {
		Thread t = new ThreadEx_06_1();				// thread instance 생성
		
//			t.start();								// thread를 Runnable상태로 전이시킴
													// 바로 실행은 안 되지만, 언젠가는 Thread Scheduler에 의해 실행됨
			String data = JOptionPane.showInputDialog("값을 입력하세요.");
			//JOptionPane은 class, showInputDialog는 static으로 지정됨
			
			System.out.println(data);
		
	}
	
}//



package sampleproj;

import javax.swing.JOptionPane;

class ThreadEx_06_1 extends Thread {
	
	@Override
	public void run() {
		
		int i = 10;									// 지역변수
		
		while(i != 0) {
			System.out.println(i--);				// 10출력 후 i값을 1감소
			// busy-waiting
			for(long k=0; k<100000000000000000L; k++);
		}
		System.out.println("카운트가 종료되었습니다.");
		
	}
}

public class ThreadEx_06 {

	public static void main(String[] args) {
		Thread t = new ThreadEx_06_1();				// thread instance 생성
		
			t.start();								// thread를 Runnable상태로 전이시킴
													// 바로 실행은 안 되지만
													// 언젠가는 Thread Scheduler에 의해 실행됨
			String data = JOptionPane.showInputDialog("값을 입력하세요.");
			//JOptionPane은 class, showInputDialog는 static으로 지정됨
			
			System.out.println(data);		
	}
	
}//

카운트가 천천히 떨어짐

suspend

t.suspend();

isinterrupted

package sampleproj;

import javax.swing.JOptionPane;

class ThreadEx_06_1 extends Thread {
	
	@Override
	public void run() {
		
		int i = 10;									// 지역변수
		
		while(i != 0 && !isInterrupted()) {			// this.isInterrupted에서 this. 생략
			System.out.println(i--);				// 10출력 후 i값을 1감소
			// busy-waiting
			for(long k=0; k<300000000000000000L; k++);
		}
		System.out.println("카운트가 종료되었습니다.");
		
	}
}

public class ThreadEx_06 {

	public static void main(String[] args) {
		Thread t = new ThreadEx_06_1();				// thread instance 생성
		
			t.start();								// thread를 Runnable상태로 전이시킴
													// 바로 실행은 안 되지만
													// 언젠가는 Thread Scheduler에 의해 실행됨
			String data = JOptionPane.showInputDialog("값을 입력하세요.");
			//JOptionPane은 class, showInputDialog는 static으로 지정됨
			
			System.out.println(data);
			
			t.interrupt();							// thread를 interrupt 시켰음
													// thread가 중지/일지정지 등은 발생하지 않음
                                                    														// 로직으로 thread의 행동을 제어해야 함
//			t.suspend();
//			t.stop();
		
	}
	
}//

  • java에서 method
    : 무조건 class명/instance.method명()/field
    : 일반변수(local variable)은 당연히 혼자 나옴
  • but, method/field 명이 그냥 달랑 혼자 나오는 경우가 있음
    : this. 생략된 것

t.interrupt(); 로 stop과 같은



ThreadEx_06_part1

package sampleproj;

import javax.swing.JOptionPane;

class ThreadEx_06_1_part1 extends Thread {
	
	@Override
	public void run() {
		
		int i = 10;									// 지역변수
		
		while(i != 0 && !this.isInterrupted()) {	// this.isInterrupted에서 this. 생략
			System.out.println(i--);				// 10출력 후 i값을 1감소
			
			try {
				Thread.sleep(2000);			
			} catch(InterruptedException e){
//				interrupt();
				System.out.println("앗, 자는 중에 interrupt가 걸렸어요");
			}
		}
		System.out.println("카운트가 종료되었습니다.");
			
		}
	}



public class ThreadEx_06_part1 {

	public static void main(String[] args) {
		Thread t = new ThreadEx_06_1();				// thread instance 생성
	
		t.start();								// thread를 Runnable상태로 전이시킴
												// 바로 실행은 안 되지만
												// 언젠가는 Thread Scheduler에 의해 실행됨
		String data = JOptionPane.showInputDialog("값을 입력하세요.");
		System.out.println(data);
		
		t.interrupt();							// thread를 interrupt 시켰음
												// thread가 중지/일지정지 등은 발생하지 않음
												// 로직으로 thread의 행동을 제어해야 함
												// 만약 interrupt를 걸었는데 이때 해당 Thread가 
												// sleep상태면,,
		
}

}//



method를 이용해서 잘 동작하는지 살펴보고, 로직으로 바꿔서 동일하기 동작하도록 만들기

ThreadEx_07.java

package sampleproj;

class ThreadEx_07_1 implements Runnable {

	@Override
	public void run() {
		
		while(true) {
			System.out.println(Thread.currentThread().getName());	// 현재Thread를 찾는다
			
			try {
			Thread.sleep(1000);
			} catch (InterruptedException e) {
				
			}
			
		}
		
	}
	
}

public class ThreadEx_07 {
	public static void main(String[] args) {
		// Runnable interface를 구현한 class의 instance를 생성
		Runnable r = new ThreadEx_07_1();
		
		Thread t1 = new Thread(r, "*");		//하는 일이 없기때문에 하는 일이 있는 r를 넣어줌
		Thread t2 = new Thread(r, "**");
		Thread t3 = new Thread(r, "***");
		
		t1.start();
		t2.start();
		t3.start();
		
		try {
			Thread.sleep(2000);		//main thread가 졸게 된다
 		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}


  • *
    가 set로 반복해서 나와야함(순서는 상관없음)

t1 suspend

package sampleproj;

class ThreadEx_07_1 implements Runnable {

	@Override
	public void run() {
		
		while(true) {
			System.out.println(Thread.currentThread().getName());	// 현재Thread를 찾는다
			
			try {
			Thread.sleep(1000);
			} catch (InterruptedException e) {
				
			}
			
		}
		
	}
	
}

public class ThreadEx_07 {
	public static void main(String[] args) {
		// Runnable interface를 구현한 class의 instance를 생성
		Runnable r = new ThreadEx_07_1();
		
		Thread t1 = new Thread(r, "*");		//하는 일이 없기때문에 하는 일이 있는 r를 넣어줌
		Thread t2 = new Thread(r, "**");
		Thread t3 = new Thread(r, "***");
		
		t1.start();
		t2.start();
		t3.start();
		
		try {
			Thread.sleep(2000);		//main thread가 졸게 된다
			t1.suspend();			//t1을 일시정지
 		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

		try {
			Thread.sleep(2000);		//main thread가 졸게 된다
			t1.suspend();			//t1을 일시정지
			Thread.sleep(2000);
			t2.suspend();
 		} catch (Exception e) {
			// TODO: handle exception
		}

		try {
			Thread.sleep(2000);		//main thread가 졸게 된다
			t1.suspend();			//t1을 일시정지
			Thread.sleep(2000);
			t2.suspend();
			Thread.sleep(2000);
			t1.resume();
 		} catch (Exception e) {
			// TODO: handle exception
		}

		try {
			Thread.sleep(2000);		//main thread가 졸게 된다
			t1.suspend();			//t1을 일시정지
			Thread.sleep(2000);
			t2.suspend();
			Thread.sleep(2000);
			t1.resume();
			Thread.sleep(2000);
			t1.stop();
			t2.stop();
			Thread.sleep(2000);
			t3.stop();
			
 		} catch (Exception e) {
			// TODO: handle exception
		}



ThreadEx_08.java

package sampleproj;

class ThreadEx_08_1 implements Runnable{
	
	//자체적으로 필드를 가짐
	boolean suspended = false;
	boolean stopped = false;	
	
	@Override
	public void run() {
		
		while(!stopped) {
			if(!suspended) {
				System.out.println(Thread.currentThread().getName());
				
				try {
					Thread.sleep(1000);
				} catch (Exception e) {

				}
			}
		}
		
	}
	
	public void suspend() { suspended = true; }
	public void resume() { suspended = false; }
	public void stop() { stopped = true; }
}

public class ThreadEx_08 {

	public static void main(String[] args) {
		
		// Runnable 객체를 공유하면 안됨 !
		ThreadEx_08_1 r1 = new ThreadEx_08_1();
		ThreadEx_08_1 r2 = new ThreadEx_08_1();
		ThreadEx_08_1 r3 = new ThreadEx_08_1();
		
		Thread t1 = new Thread(r1, "*");
		Thread t2 = new Thread(r1, "**");
		Thread t3 = new Thread(r1, "***");
		
		t1.start();
		t2.start();
		t3.start();
		
		
		try {
			Thread.sleep(2000);		// main thread sleep
			// 첫번째 thread를 일시정지할 거에요
			// Thread를 직접제어하지 않고 Thread가 가지고 있는 Runnable 객체의 
			// field값을 조절해서 Runnable객체가 가지고 있는 run() method의 
			// 로직을 변화시키는 거에요
			r1.suspend();			// thread를 제어하는게 아님. t1.suspend()
			
			
		} catch (Exception e) {

		}		
	}
	
}
	volatile boolean suspended = false;
	volatile boolean stopped = false;	

하면 제대로 나옴

package sampleproj;

class ThreadEx_08_1 implements Runnable{
	
	//자체적으로 필드를 가짐
	volatile boolean suspended = false;
	volatile boolean stopped = false;	
	
	@Override
	public void run() {
		
		while(!stopped) {
			if(!suspended) {
				System.out.println(Thread.currentThread().getName());
				
				try {
					Thread.sleep(1000);
				} catch (Exception e) {

				}
			}
		}
		
	}
	
	public void suspend() { suspended = true; }
	public void resume() { suspended = false; }
	public void stop() { stopped = true; }
}

public class ThreadEx_08 {

	public static void main(String[] args) {
		
		// Runnable 객체를 공유하면 안됨 !
		ThreadEx_08_1 r1 = new ThreadEx_08_1();
		ThreadEx_08_1 r2 = new ThreadEx_08_1();
		ThreadEx_08_1 r3 = new ThreadEx_08_1();
		
		Thread t1 = new Thread(r1, "*");
		Thread t2 = new Thread(r1, "**");
		Thread t3 = new Thread(r1, "***");
		
		t1.start();
		t2.start();
		t3.start();
		
		
		try {
			Thread.sleep(2000);		// main thread sleep
			// 첫번째 thread를 일시정지할 거에요
			// Thread를 직접제어하지 않고 Thread가 가지고 있는 Runnable 객체의 
			// field값을 조절해서 Runnable객체가 가지고 있는 run() method의 
			// 로직을 변화시키는 거에요
			r1.suspend();			// thread를 제어하는게 아님. t1.suspend()
			Thread.sleep(2000);
			r2.suspend();
			Thread.sleep(2000);
			r1.resume();			// 이거 왜 안 나오는지? 로직은 문제 없는 것 같음..
			Thread.sleep(2000);
			r1.stop();
			r2.stop();
			Thread.sleep(2000);
			r3.stop();
			
		} catch (Exception e) {

		}		
	}
	
}

로직을(while, if 변수쿼리) 이용해서 Thread의 동작 제어 : 일시정지, 다시시작, 중지

  • 왜 로직으로 바꿨나요?
    sleep(), interrupt(), isInterrupted(), yield()

yield()

: 프로그램은 조금 더 효율적으로 작성!
1초 동안 수행하세요 0.5초->양보

package sampleproj;

class ThreadEx_09_1 implements Runnable{
	
	//자체적으로 필드를 가짐
	volatile boolean suspended = false;
	volatile boolean stopped = false;	
	
	Thread t;	//내가 가지고 있는 field
	
	void setThread(Thread t) {
		this.t = t;
	}
	
	@Override
	public void run() {
		
		while(!stopped) {
			if(!suspended) {
				System.out.println(Thread.currentThread().getName());
				
				try {
					Thread.sleep(1000);
				} catch (Exception e) {

				}
			} else {
				Thread.yield();
			}
		}
		
	}
	
	public void suspend() {
		suspended = true;
		// 아마도 최대 1초 뒤에 상태를 확인해서 일시중지 작업을 시행함
		// 최대한 빨리 일시중지 상태에 돌입하려면 현재 thread에 대해서 interrupt를 걸어야 함
		t.interrupt();	//내가 가진 field를 interrupt
	}
	public void resume() { suspended = false; }
	public void stop() {
		stopped = true;
		t.interrupt();
	}
}


public class ThreadEx_09 {

	public static void main(String[] args) {
		
		// Runnable 객체를 공유하면 안됨 !
		ThreadEx_09_1 r1 = new ThreadEx_09_1();
		ThreadEx_09_1 r2 = new ThreadEx_09_1();
		ThreadEx_09_1 r3 = new ThreadEx_09_1();
		
		Thread t1 = new Thread(r1, "*");
		Thread t2 = new Thread(r1, "**");
		Thread t3 = new Thread(r1, "***");
		
		r1.setThread(t1);
		r2.setThread(t2);
		r3.setThread(t3);
		
		t1.start();
		t2.start();
		t3.start();
		
		
		try {
			Thread.sleep(2000);		// main thread sleep
			// 첫번째 thread를 일시정지할 거에요
			// Thread를 직접제어하지 않고 Thread가 가지고 있는 Runnable 객체의 
			// field값을 조절해서 Runnable객체가 가지고 있는 run() method의 
			// 로직을 변화시키는 거에요
			r1.suspend();			// thread를 제어하는게 아님. t1.suspend()
			Thread.sleep(2000);
			r2.suspend();
			Thread.sleep(2000);
			r1.resume();			// 이거 왜 안 나오는지? 로직은 문제 없는 것 같음..
			Thread.sleep(2000);
			r1.stop();
			r2.stop();
			Thread.sleep(2000);
			r3.stop();
			
		} catch (Exception e) {

		}
	}
	
}


Join()

: join()
: join(millisecond로)
: join은 instance method 특정 thread를 포함시킬 수 있음

  • join은 JVM이 가지고 있는 memory를 청소하는 garbage collector를 흉내내서 구현함
  • 가용 memory가 있음
    -> 1000이라고 가정
    -> 하나의 thread(main thead)가 일정량을 랜덤하게 사용
    -> 1000에서 랜덤값을 빼서 숫자를 줄임 => 가용 메모리량이 줄어든다
  • gc라는 thread를 이용해서 일정량으로 memory가 감소하면 memory 청소
    -> 가용 memory량을 늘려줄 거에요


코드로 알아보기

ThreadEx_10.java

package sampleproj;

class ThreadEx_10_1 extends Thread {
	@Override
	public void run() {
		for(int i=0; i<100; i++) {
			System.out.print("-");
		}
	}
}//

class ThreadEx_10_2 extends Thread {

	@Override
	public void run() {
		for(int i=0; i<100; i++) {
			System.out.print("|");
		}

	}
}//

public class ThreadEx_10 {

	public static void main(String[] args) {
		long startTime = 0;		// 시간체크해보려고 넣음
		
		Thread t1 = new ThreadEx_10_1();
		Thread t2 = new ThreadEx_10_2();
		
		t1.start();
		t2.start();
		
		startTime = System.currentTimeMillis();	//숫자로 현지시간을 표현 (밀리세컨즈단위)
		
		try {
			t1.join();			// t1이 끝날 때까지 main을 멈추고, t1이 끝나면 main 다시 실행
			t2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("소요시간 : " + (System.currentTimeMillis() - startTime));
		
		
	}
	
}//


main()이 맨 마지막에 실행됨



ThreadEx_11.java

package sampleproj;

class ThreadEx_11_1 extends Thread{
	
	// 상수 필드를 하나 선언할 거에요
	// 상수 필드는 관용적으로 대문자를 사용하고 snake case를 이용
	final static int MAX_MEMORY = 1000;
	int usedMemory = 0;
	
	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep(10000);	// 10초간 잔다
				
			} catch (Exception e) {
			}
			gc();	// memory 청소해서 memory용량을 다시 확보하는 method
			System.out.println("남음 메모리량 : freemehod");
		}
	}
	
	private void gc() {
		usedMemory = usedMemory - 300;
		if(usedMemory < 0) {
			usedMemory = 0;
		}

	}
	public int totalMemory() {
		return MAX_MEMORY;
	}
	public int freeMemory() {		// 전체 메모리에서 사용된 메모리량을 빼서
									// 현재 가용한 메모리량을 알아냄
		return MAX_MEMORY - usedMemory;
	}
}


public class ThreadEx_11 {
	
	public static void main(String[] args) {
		
	}
}
profile
기록의 즐거움 😆💻
post-custom-banner

0개의 댓글