코드스테이츠 19일차

안형준·2022년 5월 20일
0

코드스테이츠

목록 보기
19/32
post-thumbnail

1차 학습 목표

바이트 기반 스트림의 간단한 입출력 코드를 이해하고 활용합니다.
문자 기반 스트림의 간단한 입출력 코드를 이해하고 활용합니다.
파일 클래스를 이해하고 활용합니다.

👻InputStream, OutputStream
자바에서는 입출력을 다루기 위한 InputStream, OutputStream을 제공한다.
스트림은 단방향으로만 데이터를 전송할 수 있기에, 입력과 출력을 동시에 처리하기 위해서는 각각의 스트림이 필요하다.
입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉜다.
예를 들어 File을 다룰 때는 FileInputStream / FileOutputStream을 사용하고, 프로세스를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다.

👻FileInputStream
FileInputStream은 파일을 읽어올 때 사용한다.
 read() 파일의 시작부터 차례대로 바이트 단위로 읽는 용도인데, FileInputStream을 사용했으면  close()  메서드를 통해 닫아주는 게 중요하다.

BufferedInputStream
버퍼란 바이트 배열로서, 여러 바이트를 저장하여 한 번에 많은 양의 데이터를 입출력할 수 있도록 도와주는 임시 저장 공간이라고 이해하자

👻FileOutputStream
FileOutputStream은 파일을 작성하기 위해서 사용한다.
write()는 내용을 추가해 주는 역할을 한다.
FileOutputStream또한 사용했으면 close()메소드를 통해 닫아줘야 한다.
new FileOutputStream(경로, true)로 내용을 누적해서 작성할 수 있다. (기본은 false)

👻FileReader / FileWriter
자바에서는 문자 기반 스트림(FileReader와 FileWriter)를 제공한다.
문자 기반 스트림은 문자 데이터를 다룰 때 사용하는데, 이 클래스는 java.io.InputStreamReader 클래스를 상속받기 때문에, InputStreamReader 클래스의 read() 메소드를 사용하여, char를 한 글자씩 읽어올 수 있다.

read() 소드는 스트 파일에서 한 글자씩 글자를 읽어 의 char를 리턴하는데, 더 이상 읽을 글자가 없으면 -1을 리턴한다.

BufferedReader
BufferedReader를 사용하면, buffer를 사용하기 때문에, FileReader보다 좀 더 효율적으로 파일을 읽어올 수 있다.
많은 양의 데이터를 처리할 때 유리하다. 

👻FileWriter
FileWriter 클래스는 문자열을 파일에 출력할 때 사용한다.(Text파일에 저장한다는 말과도 같다.)
close 메소드를 사용하지 않으면 파일작성이 완료되지 않는다.
👻자바 가상 머신(Java Virtual Machine)
JVM은 무엇인가?
자바 프로그램을 실행시키는 도구인데, 각 운영체제에 적합한 버전이 존재한다.
이처럼 JVM은 자바 소스 코드를 운영 체제에 맞게 변환해 실행시켜준다.
이것이 자바가 운영체제로부터 독립적으로 동작하는 이유이다.

👻JVM 메모리 구조
Stack 영역이란?
스택은 흔히 LIFO라는 키워드로 설명된다.(“Last In First Out”)
스택
- 밑이 막힌 상자라고 생각한다면, 위로 하나씩 담길거고 위에 있는 메서드가 실행되는 동안에는 아래에 있는 메서드는 대기 상태로 바뀐다. 
- 위에 있는 메서드가 종료될 시 스택에서 제거되며, 아래에 있는 메서드가 실행 상태로 바뀐다.
호출 스택
- 메서드 수행에 필요한 메모리가 제공되는 공간
- 메서드가 호출되면 호출스택에 메모리 할당, 종료되면 제거
- 스택의 아래쪽 메서드가 위의 메서드를 호출한 것
- 스택 맨 위 메서드 하나만 실행 중, 나머지는 대기중

Heap 영역이란?
JVM에는 단 하나의 Heap 영역이 존재하는데, JVM이 작동되면 이 영역은 자동 생성된다.
그리고 이 영역안에 객체나 인스턴스 변수, 배열이 저장된다.
Person person = new Person();
위 문장을 볼 때 참조변수 person은 스택(Stack)영역에, Person 인스턴스는 힙(Heap)영역에 저장된다.
정리하자면, Heap 영역은 실제 객체의 값이 저장되는 공간이다.

👻Garbage Collection
가비지 컬렉션은 프로그램에서 더이상 사용하지 않는 객체를 찾아 삭제하거나 제거하여 메모리를 확보하는 일을한다.
만약 아무도 인스턴스를 참조하고 있지 않다면, 더 이상 메모리에 참조변수가 가리키던 인스턴스가 존재해야 할 이유가 없다.
가비지 컬렉터는 이렇게 아무한테도 참조되고 있지 않은 객체 및 변수들을 검색하여 메모리에서 점유를 해제하여 메모리 공간을 확보할 수 있다.

힙(Heap)영역에서 객체가 얼마나 살아있냐에 따라 Young, Old영역 2가지로 나눈다.

Young 영역에서는 새롭게 생성된 객체가 할당되는 곳이고 여기에는 많은 객체가 생성되었다 사라지는 것을 반복한다.
이 영역에서 활동하는 가비지 컬렉터를 Minor GC라고 한다.

Old 영역에서는 Young영역에서 상태를 유지하고 살아남은 객체들이 복사되는 곳으로 보통 Young영역보다 크게 할당되고 크기가 큰 만큼 가비지는 적게 발생한다.
이 영역에서 활동하는 가비지 컬렉터를 Major GC라고 한다.

Young 영역과 Old 영역은 서로 다른 메모리 구조로 되어 있기 때문에, 세부적인 동작 방식은 다르지만 기본적으로 가비지 컬렉션이 실행될때는 다음의 2가지 단계를 따른다.

1.
Stop The World
Stop The World는 가비지 컬렉션을 실행시키기 위해 JVM이 애플리케이션의 실행을 멈추는 작업이다. 가비지 컬렉션이 실행될때 가비지 컬렉션을 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업은 중단되고, 가비지 정리가 완료되면 재개된다.

2.
Mark and Sweep

이 단계에서는 두가지 일을 수행하는데 먼저, Mark(사용되는 메모리와 사용하지 않는 메모리를 식별하는 작업)과 Sweep(Mark단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업)이 일어난다. 정리하면 Stop The World를 통해 모든 작업이 중단되면, 가비지 컬렉션이 모든 변수와 객체를 탐색해서 각각 어떤 객체를 참고하고 있는지 확인한다. 그리고 사용되고 있는 메모리를 식별해서(Mark) 사용되지 않는 메모리는 제거(Sweep)하는 과정을 진행한다.
👻쓰레드
프로세스== 자원+ 쓰레드
1 프로세스에 1 이상 쓰레드 필요
프로세스 : 쓰레드 = 공장 : 일꾼
새로운 쓰레드를 생성하는 것이 새로운 프로세스 생성보다 비용대비 효율적
장점 : 효율적인 자원 사용, 응답성 향상
단점 : 동기화 주의 , 교착상태 발생위험(서로 대치), 기아 가능성 O
잘 동작하는, 에러 없는 코드가 중요하다.

👻쓰레드의 구현과 실행
- 쓰레드 구현과 실행
-> Thread 클래스 상속, Runnable if구현
- 쓰레드의 실행 : start(), 쓰레드를 생성 후 start()를 호출해야 작업시작 
-> 언제(누가 먼저) 실행될지는 os스케쥴러에 의해 결정
- start() & run() why ? : start()는 새로운 call stack 생성(서로 독립적 작업 가능), run()(하나의 호출 스택을 하나의 쓰레드가 실행)

👻싱글 쓰레드와 멀티 쓰레드, 쓰레드의 I/O 블락킹
- main 쓰레드 : main메서드에서 코드를 수행하는 쓰레드
- 쓰레드는 사용자 쓰레드와, 데몬 쓰레드 두 종류가 있다
- 실행 중인 사용자 쓰레드가 하나도 없으면 프로그램은 종료된다
- ContextSwitching : A작업 -> B작업
- 멀티쓰레드 장점 : 시간이 좀 더 걸리더라도 여러 작업을 동시에 할 수 있다, 작업을 좀 더 효율적으로 할 수 있다 ex) 채팅 프로그램, 카카오톡
- I/O 블락킹 : 입출력 시 작업 중단, 자원을 효율적으로 사용하기 위해(놀고있는 쓰레드를 최소화)

👻쓰레드의우선순위. 쓰레드 그룹
- 쓰레드 그룹 : 관련 있는 쓰레드들을 묶어둔 그룹
- 모든 쓰레드들은 최소 1개의 쓰레드 그룹에 속해있다
- 쓰레드 우선순위 설정 메서드 : setPriority(num);
- os 별로 기본적으로 구성된 쓰레드 우선순위 테이블이 있다
- mac에서 쓰레드 상태를 보고 싶다면 : top(터미널에서)

👻데몬쓰레드, 쓰레드의 상태
데몬 쓰레드 = 일반 쓰레드의 보조역할.
무한루프, 조건문 이용, 
대기상태 -> 특정조건이 충족되는 경우(if문)에만 작업을 수행하고 -> 다시 대기상태 ( 일반쓰레드가 하나도 남지 않으면 자동종료된다. )
void setDeamon(boolean on)는, start()가 호출되기 전에 실행해야함.
void sleep(), void yield() -> static, 즉 스레드 자신에게만 적용가능.

👻sleep(), interrupt()
- 쓰레드 실행 제어 : sleep, yield(양보)
- sleep() : 현재 쓰레드를 지정된 시간동안 멈추게 한다, 예외 처리를 해야한다(InterruptedException이 발생하면 깨어남), 필수 예외처리 (예외처리를 이용해서 깨우므로)
	- 쓰레드가 멈추는 경우 : 1) time up, 2) interrupted (깨우는 것)
	- try-catch 예외 처리가 불편해서(매번 예외처리 하는 불편함) 대신 delay() 메서드를 따로 생성해서 호출
	- 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능하다.(반드시 클래스 이름으로 static 메서드로 호출하여 사용해라 - 오해의 소지 방지)

- interrupt() : 대기상태(WAITING)인 쓰레드를 실행대기 상태(RUNNABLE)로 만듦, 쓰레드를 중단하거나, 중단시킨 쓰레드를 재개하고 싶을 때 사용
	- interrupt() : interrupted상태를 false -> true
	- isInterrupted() : 쓰레드의 interrupted상태를 반환.
	- interrupted() : 현재 쓰레드의 interrupted상태를 알려주고, false로 초기화

👻suspend(), resume()
- suspend(), resume(), stop()은 dead lock 때문에 deprecated(사용하지 않는 것을 권장)한다.
각각 일시정지, 작업 재개, 강제 소멸을 의미한다.
-> sleep(), interrupt() 를 써라
volatile 자주 바뀌는 값에 사용하며 원본 값을 그대로 사용하는지,  cpu cache에 복사해서 가지고 있는지에 따라 다르다.
-> volatile 키워드는 원본값을 쓰라고 설정하는 키워드

👻join(), yield()
- join() : 다른 쓰레드가 끝나길 기다리기(blocking)
- yield() : static method(자기 자신만을 제어 가능)중에 하나로 다른 쓰레드에게 양보하며 자기 자신을 실행대기 상태로 만든다.
-> 멀티 쓰레드로 구성하더라도 하나의 쓰레드가 작업을 독점할 수도 있으므로, 
sleep(), inturrupt(), yield() 를 적절히 사용하는게 좋다.
※ yield()는 OS스케쥴러에 의해 제어되므로 반드시 동작한다고 장담할 수 없다.

👻쓰레드의 동기화
- 쓰레드의 동기화(synchronization) : 
1) 멀티 쓰레드 프로세스에서는 다른 쓰레드의 작업에 영향 미칠 수 있음
2) 진행중인 작업이 다른 쓰레드에게 간섭받지 않게 하려면 -> 동기화
3) 동기화하려면 간섭받지 않게 하는 문장(sentence)들을 임계영역으로 설정
4) 임계영역은 락(lock)을 얻은 단 하나의 쓰레드만 출입가능(객체 1개에 락 1개)
- synchronized를 이용한 동기화 :
1) synchronized로 임계영역을 설정하는 방법 2가지 : 메서드 전체(가급적 피함), 특정한 영역을 임계영역으로 지정

👻wait()과 notify()
동기화의 효율 개선 목적 -> wait(), notify() 사용.
wait( ) - 객체의 락을 풀고 스레드를 해당 객체의 waiting pool에 넣는다.
notify( ) - 무작위로 waiting pool에 있는 스레드 하나를 깨운다.
notifyAll( ) - 다 깨움 스레드 하나만 락을 얻는다.
하지만 wait(), notify()는 호출의 대상이 불분명하다. ->   이러한 단점을 해소한 것이 lock&condition

오늘은 파일 입출력(I/O), 쓰레드(Thread), 자바 가상 머신(Java Virtual Machine)에 대한 개념을 학습했다.
저번 스트림부터 쓰레드까지 완전히 새로운 것을 배우는 기분이 들어 역시 어렵다는 생각이 들었다. 또한 단순히 코딩을 하는 것이 아닌 자바의 구조에 대해서도 함께 공부를 했는데, 개발이란 분야는 단순히 코딩을 잘하는 것이 아닌 컴퓨터의 구조에 대해서도 잘 알고 있는 것이 중요하다는 생각이 들었다.
앞으로도 컴퓨터와 더 친해지면서 따로 이것저것 더 공부해볼 생각이다.
오늘도 고생했고 내일도 파이팅!

profile
개발 공부

0개의 댓글