2주차 12/09(금)

하이·2022년 12월 9일
1

수업

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

Join

thread 2개가
main thread 가 700쯤 가면 1000이 넘지 않도록, 다른 method가 (10초마다 300씩 차감) 700을 가져가서 400으로 제어함

package sampleproj;

// 이 thread의 instance를 생성해서 실행하면
// 10초마다 일정량의 메모리사용량을 감소시킴
class ThreadEx_11_1 extends Thread{

	final static int MAX_MEMORY = 1000;
	int usedMemory = 0;
	
	@Override
	public void run() {
		while(true) {					// 무한루프
			try {
				Thread.sleep(10000);	//try~catch문 씌워주기
			} catch (InterruptedException e) {

			}
			gc();						//	10초간 잤다 깨면서 메모리 청소 좀 해라 ~
			System.out.println("남은 메모리량 : " + freeMemory());
		}
	}

	public void gc() {
		usedMemory -= 300;				// usedMemory = usedMemory - 300;
		if(usedMemory < 0) {
			usedMemory = 0; 			//메모리값이 마이너스인 경우는 없으니까 0
			
		}
	}
	public int totalMemory() {
		return MAX_MEMORY;
	}
	
	public int freeMemory() {			// 가용 메모리
		return MAX_MEMORY - usedMemory;	
	}
}


public class ThreadEx_11 {
	
	public static void main(String[] args) {
		
		ThreadEx_11_1 t = new ThreadEx_11_1();
		t.setDaemon(true);
		t.start();						// start 하면 run이 실행됨
		
		int requiredMemory = 0;
		
		for(int i=0; i<20; i++) {
			requiredMemory = ((int)(Math.random()*10)) * 20;
							// Math.random 0<= 난수 < 1 사이의 난수값을 도출
							// 0 ~ 10 인데, 정수화 시켜서 소수점이 날라가서 0 ~ 9까지의 난수값
							// 0 ~180 , 0, 20, 40, 60, ... 180
			
			// 위에서 구한 필요한 메모리량이 사용할 수 있는 메모리 량보다 크거나
			// 혹은 전체 메모리의 60% 이상을 사용했을 때 GC를 깨울 거에요
			if((t.freeMemory() < requiredMemory) || 
					t.freeMemory() < t.totalMemory() * 0.4) {
				t.interrupt();	// 자고 있던 memory를 깨움
			}
			
			t.usedMemory += requiredMemory;	// 사용된 메모리량을 누적시킴
			System.out.println("남은 메모리량 : " + t.freeMemory());			
		}		
	}
}

로직 상으로는 마이너스가 나올 수 없는데 ,,어디선가 허점이 있다
=> 메모리 청소하면서도 main이계속 돌고있어서 그럼
메모리 청소할 때 main method를 잠시 멈추고, 청소 후 다시 main method가 실행해야함 (순차처리가 필요)
=> 이때 join이 필요

			if((t.freeMemory() < requiredMemory) || 
					t.freeMemory() < t.totalMemory() * 0.4) {
				t.interrupt();	// 자고 있던 memory를 깨움
				
				try {
					t.join(100);	// 0.1초동안 sleep에서 깨어나서 메모리를 청소함.
									//인자없이 사용하면 무한루프에 빠지기 때문에 숫자를 넣어줌
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
			}
			
			t.usedMemory += requiredMemory;	// 사용된 메모리량을 누적시킴
			System.out.println("남은 메모리량 : " + t.freeMemory());			
		}



Thread의 동기화(Synchronization)


이런 현상이 발생하지 않도록 하나의 Thread가 특정 작업을 마치기 전까지 다른 Thread에 의해서 방해 받지 않도록 처리해야 함 : 동기화

① Critical Section(임계영역)
② Lock (락, 잠금)
: monitor라고 하기도 함



공용객체

: class를 정의
: 여기에 예금잔액 데이터가 있음
:

--사진 넣기

코드로 알아보기

ThreadEx_12.java

package sampleproj;

class Account {
	//생성자
	public Account() {
		
	}
	
	public Account(int balance) {
		super();
		this.balance = balance;
	}

	// field
	private int balance;
	
	
	//business method
	public void withdraw(int money) {
		if(balance >= money) {
			try {
				Thread.sleep(1000);		//현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
			} catch (Exception e) {
				// TODO: handle exception
			}
			balance -= money;
		}
	}
	
	
	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}
	
	
}


class ThreadEx_12_1 implements Runnable {
	//field
	Account acc = new Account(1000);
	
	@Override
	public void run() {
		
		while(acc.getBalance() > 0 ) {
			int money = (int)(Math.random() * 3 + 1) * 100;
						// 0 ~ 3인데 +1 해서 1 ~ 4
			acc.withdraw(money);	//공용객체의 출금처리
			System.out.println("남은 금액 : " + acc.getBalance());
					
		}
		
	}
}




public class ThreadEx_12 {
	public static void main(String[] args) {
		ThreadEx_12_1 r = new ThreadEx_12_1();
		
		Thread t1= new Thread(r);
		
		t1.start();
	}
}

Thread 2개 동시 진행

public class ThreadEx_12 {
	public static void main(String[] args) {
		ThreadEx_12_1 r = new ThreadEx_12_1();
		
		Thread t1= new Thread(r);
		Thread t2= new Thread(r);
				
		t1.start();
		t2.start();
	}
}


=> 문제 발생. 마이너스 나옴

thread 1이 자는 동안 thread 2가 200차감함
-> thread 1이 깨어나서 또 200차감
-> 남은 잔액이 -100가 됨

해결하기 위해 !
Synchronized keyword를 이용 : Lock, Monitor를 획득할 수 있음

① method 앞에 붙여서 동기화 method를 만든다
: method를 호출하면

  • 문제점 : method의 실행이(코드가) 길다
    전체가 아닌 일부를 동기화 시킴
	
	// business method
	// synchronized method (동기화 메소드)
	// 이 메소드를 실행한 Thread가 먼저 Lock(Monitor) 획득.
	// 하나의 thread가 메소드를 호출하면 나머지 하나는 block됨 !
	public synchronized void withdraw(int money) {
		// balance => 300
		// thread 1 => 200 차감
		// thread 2 => 200 차감
		if(balance >= money) {
			try {
				Thread.sleep(1000);		//현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
			} catch (Exception e) {
				// TODO: handle exception
			}
			balance -= money;
		}
	}

	public void withdraw(int money) {
		// ~~~
		// 여기 코드는 동기화 안 됨
		// ~~~
		
	synchronized(this) {
			if(balance >= money) {
				try {
					Thread.sleep(1000);		//현재 수행되는 thread의 method를 재움. 일부러 확인하기 위해
				} catch (Exception e) {
					// TODO: handle exception
				}
				balance -= money;
			}
		}
	
		// ~~~
		// 여기 코드는 동기화 안 됨
		// ~~~
				

	}



임계영역 code가 다 실행되어야 다른 Thread가 실행될 수 있다
=> 너무 오래 걸림 : 다른 Thread가 오래 기다려야 함

  • wait()
    : 현재 실행 중인(critical section) thread가 Lock을 놓고 wait 상태로 전환함
  • notify()
    : wait에 의해 일시정지된 Thread 중 하나를 Runnable 상태로 전환시킴

예제

1초마다 자신의 이름을 출력하는 Thread를 2개 생성한다
하지만, 두개의 thread의 실행 순서는 알 수가 없다
우리가 만들고 싶은 건 : 두개의 thread가 번갈아 가면서 자신의이름을 출력하는 코드를 구현
=> wait(), notify() 이용하기
wait- Synchronized 일어남

https://scshim.tistory.com/243 내가 찾은 참고자료

Thread의 이름은 따로 field 잡을 필요 없음

공용객체,

package sampleproj;

// 1. 공유객체를 생성하기 위한 class
class Shared {
	
	// 공유객체의 공유 메소드
	public synchronized void printName() { // 2.						// 11.동기화
		try {				  				// 3.
			for(int i=0; i<10; i++) {
				Thread.sleep(1000);
				System.out.println(Thread.currentThread().getName());
				notify();												// 13. 여기에 위치해야 함
				wait();													// 12.첫번째thread를 재우고 두번째thread 실행->wait
				//notify();	 를 여기다 쓰면 실행이 안 됨. 이미 들어가있는 애를 끄집어 내고 다시 실행 시켜줘야함
				
				
				
			}
		} catch (Exception e) {
		}
	}
}


class ThreadEx_13_1 implements Runnable{ // 4.
	
	public ThreadEx_13_1(Shared shared) {// 6.
		super();
		this.shared = shared;
	}
	
	private Shared shared;				// 5.

	@Override							// 7. 본인이 가진 공유객체의 공유 method를 가져옴. printName
	public void run() {
		shared.printName();
		
	}
}
public class ThreadEx_13 {
	
	public static void main(String[] args) {
		// 8. 공유객체 만들기
		Shared shared = new Shared();											// 9.공유객체를 가지고
		
		Thread t1 = new Thread(new ThreadEx_13_1(shared),"첫번째 쓰레드");			// 10.runnable객체를 만들고 -> thread 만들고 -> run 호출 -> 공유객체에 대해서 printName
		Thread t2 = new Thread(new ThreadEx_13_1(shared),"두번째 쓰레드");
		
		t1.start();
		t2.start();
	}
	
}



Java IO

: Java Input/Output
: Java 입출력에 관련된 내용
Java.io package로 제공(class가 제공)
Stream : 데이터 전송 통로, instance로 존재(class가 제공)

확장된 것 => Java NIO

Java에서 program -> File에 데이터를 저장

① Stream은 2가지 종류가 있음
: 입력 Stream / 출력 Stream 이 따로 존재함
: 단방향 스트림
② Stream은 FIFO구조(First in First out) 선입선출 구조
Stream을 통해 A-B-C-D
--사진

③ Stream을 결합해서 사용할 수 있음
Stream : 전체 Stream을 지칭 (Input/Output)
--사진

④ Stream은 byte단위(숫자)의 Stream과 문자 단위(Reader,Writer)의 Stream으로 구분됨

  • 기본 Stream은 사용하기 불편함!
    특히 문자열 기반의 입출력은 많이하는데, 기본 Stream으로는 너무 힘들다
    inputStream 겉에 inputStream Reader => Stream 결합

  • 기본적으로 우리에게 제공된 Stream.
    system.out -> Output Stream의 객체
    system.in -> InputStream의 객체

코드로 알아보기

JavaIO 연습 프로젝트 생성

Exam01_KeyboardInput.java

package sample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Exam01_KeyboardInput {

	public static void main(String[] args) {
		
		System.out.println("키보드로 한 줄을 입력하세요!");
		// 키보드로부터 입력을 받으려면, 데이터 연결통로(Stream)이 있어야 함
		// System.in이 제공되는데.. InputStream class의 객체 => 사용하기 너무 불편 !
		// 문자기반의 데이터를 받기를 원함 => Reader를 하나 만들어야 함
		// new InputStreamReader(System.in) 이렇게 Stream을 결합해서
		// 조금 더 편한 문자 기반의 통로를 열었음 그럼에도 불구하고 불편함 !
		// 조금 더 편한 문자 기반의 데이터 입력 연결통로를 만들어 볼 거에요
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		try {
			String s = br.readLine();
			System.out.println("입력받은 데이터는 : " + s);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}

결국 Stream이 데이터 연결 통로

  • 출력
    : BufferedReader 이용

  • 출력

    • 모니터 : System.out 제공된 Stream 이용
    • 일반 용도 : PrintWriter 이용
      • 목록 1.2

예를 들어) HashMap을 File에 저장 !
=> Stream을 통해 객체를 읽어오고/내보내려면 어떻게 해야하나요?

Exam02_ObjectStream

package sample;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;

public class Exam02_ObjectStream {
	
	public static void main(String[] args) {
		
		// 먼저 Stream을 통해 내보낼 HashMap을 간단히 만들어보자
		HashMap<String, String> map = new HashMap<String, String>();
		
		map.put("1", "홍길동");
		map.put("2", "신사임당");
		map.put("3", "강감찬");
		
		// 실제 파일을 생성하려면 당연히 자바쪽에서 File객체를 만들어야 함
		File file = new File("readme.txt");
		
		try {
			FileOutputStream fis = new FileOutputStream(file);
			ObjectOutputStream oos = new ObjectOutputStream(fis);
			
			oos.writeObject(map);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}



Network

Internet

: 물리적인 프레임워크

computer라는 물리적인 장치
실행적인 program이

② Internet을 이용
: 물리적인 network 위에서 수행되고 있는 program을 이용 => Service

  • 대표적인 service => Email/ World Wide Web Service/ Torrent ../ FTP ...

③ Internet에 연결되어 있는 각 computer(안의 여러개의 process가 다른 process와)가 data 통신을 하려면 주소가 필요함

  • IP address (주소)는 NIC에 할당됨 : Network Interface Card
    • 주소 : 4자리 숫자로 구성됨 IPv4
      ex) 123.225.0.17 = 0~255/ 0~255/ / 0~255
      (콘솔창에 ipconfig 쳐보기 - 맥북 검색)

    • IP 주소는 논리적인 주소로 임의로 변경이 가능
      => 결국 물리적인 주소가 필요 : 이를 MAC address 라고 함

④ DNS(Domain Name System)
: IP 주소는 숫자라서 기억하기 힘들기 때문에 이를 문자로 표현하기로 함
ex) www.naver.com

  • (Domain Name -> IP 주소 -> MAC 주소) 통신이 진행됨

⑤ Protocol
: 국가 간의 조약

  • CS에서의 의미 : 데이터 통신을 위해 정해놓은 약속/규칙 (ex) 군대 전화 - 통신 보안)
    • 모든 데이터 통신에는 protocol이 존재함
      web service -> HTTP -> 복잡

⑥ Socket
: 결국 너무 복잡하고 어려워서 socket 이라는 개념이 나옴


chatting이 제대로 돌기 위해서는 (Thread -> 동기화 -> 공유객체)

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

0개의 댓글