본문 바로가기

IT/공부

[프로그래밍] Data Source/Data Target, BufferedReader, Thread

<<<이클립스 사용법>>>
for ctrl+space => 자동으로 for문 만들어줌.
삼항연산자 : 편한데 가독성 떨어짐
generate equals 있음.

<<<e.getMessage()>>>
예외 생성자에 String 받는거 생성하면 그 메세지 가져오는 메서드

<<<reference data type은 항상 equals method로 비교하자>>>

<<<runtime 계열 exception은 try-catch 안해도 컴파일 된다. 그리고 throws도 안해도 된다>>>

=====================================

<<<instanceof>>>
is a 관계인지 파악하는 키워드. true/false로 나온다.

<<<java.io 패키지>>>
외부에서 JVM으로 들여오고 내보낼 때 사용하는 Bean들을 모아놓은 패키지로 interface 기반 모델링이 되어 있다. 
InputStream, OutputStream이 계열 최상위 abstract class이다.

<<<Data Source, Data Target>>>
외부에서 JVM으로 읽어들일 때 keyboard를 읽거나 file을 읽거나 network를 읽기도 한다. 이렇게 구체적으로 입력되는 것을 이야기하지 않고, Data Source라는 말을 사용한다.
Data Target은 어디로 혹은 어떻게 데이터를 내보낼지를 가리킨다. 모니터로 내보내거나, 네트워크로 내보내거나 프린터로 내보낼 때 모니터, 네트워크, 프린터를 Data Target이라 한다. 

<<<BufferedReader>>>
Reader의 하위 클래스.
InputStream is = System.in;
is.read();
Reader r = InputStreamReader(is);
r.read();
BufferedReader br = new BufferedReader(r);
br.readLine();
is.read()를 이용하면 binary로 처리하기 때문에, 한 byte씩 읽어들이기 때문에 작업해야 할 게 많다. 또한 읽어들일 내용이 없을 때까지 반복해줘야 하기 때문에 반복문이 엄청 많이 돌아간다. 
r.read()도 마찬가지이다.
Buffered Reader는 Reader의 하위 class로 read()메서드를 구현하고 있으나 더 효율적인  readLine()메서드도 가지고 있다.
API를 확인하며 사용할 수 있는데, readLine()는 return type이 String이다. read()메서드는 한 문자씩, 1 byte씩 읽어들였다면 readLine()은 한 줄씩 읽어들인다. 작업해야 할 양이 줄어드는 것이다. 
readLine()은 한 줄임을 인식하는 csv는 "\n"이다. "\n"을 csv로 인식하기는 하지만 실제로 읽어들이지는 않으므로 "\n"을 뒤에 append 해주거나 (BufferedWriter data type이라면) newLine() 메서드를 사용해 한 줄 계행시켜준다.

<<<EOF>>>
End of File. 파일에 더 이상 읽어들일 내용이 없다는 뜻이다. FileInputStream에서는(혹은 FileReader에서는) -1을 return 했지만 BufferedReader의 readLine()은 null을 return 한다. 

<<<sink stream, filter stream>>>
java io의 특징에는 FIFO, I/O block, 유연한 구조, 단방향 모델링이 있는데, sink stream, filter stream 개념은 유연한 구조를 설명하는 개념이다. 
Sink stream은 Data를 직접 주고 받는 단순 입출력 Stream을 말한다. 예를 들어 키보드로 입력했을 때의 System.in이나 FileInputStream type 등이 Sink steam이다. 
이를 "통과시킨다"고 하는데 primitive data type의 wrapping과 비슷한 것 같다. System.in을 InputStreamReader 데이터 타입으로 받아 Reader 타입으로 사용할 수 있는 것처럼 통과시킨 Stream을 Filter Stream이라 한다.
큰 데이터 타입이 작은 데이터타입의 인스턴스를 받는 묵시적 형변환을 통해 다형성을 구현하는 방법이다.

<<<파일 위치 입력할 때 "C:\text.txt"로 입력하면 \t를 탭으로 인식한다. 이 때는 "C:\\text.txt"라고 입력해야 한다.>>>

<<<write(char[] cbuf, int off, int len) 는 parsing 할 때 쓰이는 메서드로, csv가 있는 인덱스를 찾아 그 다음 인덱스부터 출력할 때 쓰이는 메서드이다>>>

<<<keyboard가 System.in 이다.>>>

<<<VO, Serializable>>>
데이터를 주고 받을 때 하나씩 주고받는 것보다 뭉탱이로 주고받는게 더 효율적이다. 뭉탱이로 주고받을 때에는 csv를 이용해서 구분해주며, 받은 데이터를 사용할 때에는 parsing이 필요하다. 그렇다면 처음부터 객체를 주고받으면 parsing도 필요하지 않고 뭉탱이로 주고받을 수 있고 훨씬 효율적이다. 주고받는 객체는 VO라고 한다. VO는 ValueObject로 정보만 가지고 있는 객체를 뜻한다. (DTO와도 같은 말이다. Data Transfer Object의 줄임말이다.) 객체를 보내고 받으려면 반드시 Serializable marker interface를 구현해야한다. marker interface는 구현할 때 OverRiding해야 하는 method가 없는 인터페이스 클래스를 말한다. marker는 컴파일러compiler 나 JVM에게 알려주는 표시 mark를 한다는 의미이다. 얘는 외부로 나갈 VO야 라고 말해주는 것이다. Serializable 을 implements 한 클래스는 JVM이나 컴파일러가 이 클래스를 보고 외부로 내보내는 작업을 한다. 
Serializable은 객체 직렬화라고도 한다. API의 80%가 Serializable을 구현했다.

<<<null String>>>
String abc = ""; //==> null String
String abcd = null;
이 둘은 다르다.
abc는 String abc = new String();와 같은 의미, default 생성자로 생성한 것과 같은 의미이다. 
abc.length();는 0이지만, abcd.length();는 NullPointException이 발생한다.
로그인 시 아이디나 비밀번호를 입력하지 않고 로그인버튼을 누르면 null String으로 판단한다.

<<<File System>>>
우리는 보통 .txt나 .hwp 등을 파일이라 한다. 그러나 전산에서는 디렉토리와 우리가 부르는 파일을 포함한 모든 것을 File System 파일시스템이라 한다. 디렉토리를 parent, 파일을 child라 하며 이를 통틀어 path name이라고도 한다. 

<<<절대경로 Absolute path, 상대경로 path>>>

<<<Thread>>>
process = 어플리케이션의 실행 단위.
thread = process의 작은 실행 단위. 
스레드는 여러 작업을 동시에 진행하는 방법 중 하나이다. 
컴퓨터는 기본적으로 한 번에 하나의 작업밖에 수행하지 못한다. 그러나 여러 프로세스를 CPU와 연결할 때 잠깐씩 연결하고 끊는다면, 그리고 그 시간 간극을 극도로 짧은 시간으로 한다면 마치 일이 동시에 진행되는 것처럼 보인다. 이처럼 프로세스와 CPU를 짧게 연결하고 끊어서 동시에 일처리 되는 것처럼 보이게 하는 것을 멀티 태스킹이라 한다. 컴퓨터의 사양을 파악해서 프로세스를 CPU와 연결하고 끊는 작업을 OS에선 process scheduler가 한다. 
여러 작업을 할 때 프로세스를 여러 개 작업하는 방법이 있고, 하나의 프로세스에서 여러 스레드를 사용하는 방법이 있다. 여러 프로세스를 켜는 것을 엑셀 창을 세 개 띄워 놓는 것으로, 스레드 여러 개를 엑셀 창 하나에 Sheeet1, 2, 3에 작업하는 것으로 생각하면 된다. 그러나 프로세스를 여러 개 띄워 놓으면 처리 속도가 빠르지 않고 실행이 버벅인다. 이는 "process 발생 비용이 고가다" 라고 말할 수 있다. 이보다 효율적인 것이 여러 작업을 할 때 여러 스레드를 이용하는 방법인데 CPU입장에서 하나의 프로세스만 처리하면 되기 때문에 편하다. 
사용자 입장에서는 멀티 스레드를 이용하면 프로세스 여러 개를 돌리는 것과 달리 정보 전달 혹은 참조 전달 시 IO가 필요 없다는 것이다. 프로세스와 프로세스 간 데이터 전달은 복잡하다. 외부의 자원이 필요하기 때문이다. 만약 엑셀에서 쓰던 표를 PPT에 옮기려면 프로세스 외부, OS에 해당 내용을 복사해야한다. 클립보드를 생각하면 된다. 외부자원이 필요하다는 것은 IO를 사용한다는 것이다. 그러나 스레드간의 데이터 교환은 하나의 process이기 때문에 외부자원 IO 없이 참조할 수 있다.  
OS에서 process scheduler의 작업을 JVM에서 .class 파일을 실행할 때에는 thread scheduler가 실행시킬 thread스레드를 등록해준다. 스레드는 Runnable로 등록이 되었다가 thread scheduler가 Run 할 수 있도록 올려줬다가 다시 Runnable로 끌어내렸다가 한다. main만이 스레드 스케줄러에 실행시켜달라 요청하는 것이 가능하지만, start() 메서드를 이용하면 스레드 스케줄러에 실행시켜달라 요청할 수 있다. 메인 스레드 하나만 있는 것을 싱글 스레드(single-thread) 라고 하며, 스레드가 여러개인 것을 멀티 스레드(Multi-thread) 혹은 다중 스레드라 한다.
start()는 Thread class에 있는 메서드로, 내부적으로 run()을 호출해 실행시킨다. 따라서 start()를 이용하려면 Thread Data type이어야 한다. 

start()를 사용하는 두 가지 방법(Thread를 구현하는 두 가지 방법)이 있다. 
첫째는 객체지향의 개념에서 이 클래스가 Thread 클래스가 되면 된다. Thread를 확장한다는 의미이고 공유한다는 의미이며 상속받는다는 뜻이다. Thread 클래스를 확장하면 run()과 start()가 생성된 인스턴스 안에 있기 때문에 스레드를 구현할 수 있다.
그러나 자바는 다중 상속을 금했다. 따라서 다른 클래스를 확장하면서 스레드를 사용하려면 확장으로 할 수 없을 때가 있다. 이 때에는 Runnable interface class를 implement 하면 된다. start()를 사용하려면, start()는 run()을 내부적으로 호출하기에 반드시 run()가 있어야 한다. Runnable에는 abstract method로 run()이 있기에 이를 구체화 한 클래스에는 반드시 run()가 있게 된다. 그리고 이 때에 strat()는 Thread 클래스에만 있기 때문에 Thread 인스턴스를 생성해준다. API에서 Thread의 생성자를 보면 전달인자가 Runnable을 데이터타입인 생성자가 있다. 스레드를 사용하려는 Runnable을 구현한 인스턴스에는 반드시 run()이 있기 때문에 Thread 생성자에 이 인스턴스를 넣어주고 Thread data type의 인스턴스에서 .start()를 호출하면 스레드 스케줄러에 등록할 수 있다. 
 
<<<스레드 처리 참여: 라운드 로빈, 우선순위(Multi-queue멀티큐), sleep()>>>
스레드 처리 방법은 라운드 로빈 스케줄링으로, 라운드 로빈 스케줄링(Round Robin Scheduling, RR)은 시분할 시스템을 위해 설계된 선점형 스케줄링의 하나로서, 프로세스들 사이에 우선순위를 두지 않고, 순서대로 시간단위(Time Quantum)로 CPU를 할당하는 방식의 CPU 스케줄링 알고리즘이다. 
thread는 컴퓨터에 등록된 시간적 순서로 교차 실행될 확률이 높다. 즉 thread는 실행만 가능할 뿐 실행 결과 예측은 불가능하다. 그러나 sleep()과 우선순위를 할당하는 방법으로 thread 작업에 일부 참여가 가능하다. sleep()은 run()안에 하는 작업이다. 
//method
public void run() {
for(int i = 0; i<100; i++) {
System.out.println(name+" : "+i);
 //sleep()
try{
Thread.sleep(100);
}catch(InterruptedException e){
System.out.println(e);
}
}
}
sleep(milli sec): 스레드1이 Runnable에서 thread scheduler에 의해 Run 되어 실행되다가 sleep 메서드를 만나면 해당밀리세컨만큼 sleep pool이라는 곳에 들어간다. 해당 밀리세컨이 지나면 나온다. 그동안 스레드1이 Run되지 않으므로 스레드2가 Run 되다가 다시 sleep 메서드를 만나 sleep pool에 들어간다. sleep pool에서 먼저 들어간 스레드가 먼저 나올 것이기 때문에 스레드1이 다시 나와 Runnable에 들어가고 Run 된다. 이런 방법으로 thread 실행 과정에 참여할 수 있다.

Runnable도 Queue 구조이기 때문에 먼저 들어간 thread가 먼저 Run 된다. 이 때 Multi-queue 구조(구멍 뚤린 큐)를 이용하면 스레드가 Runnable을 만나는 과정을 조절할 수 있다. multi-queue는 Queue 구조에 들어가는 입구가 하나 이상인 것이다. 중간에서 끼어들 수 있는 입구가 있는 구조이다. 따라서 Runnable과 가까운 queue 입구로 들어간다면 더 자주 실행될 것이다. 이때 Runnable과 가까운 Queue 입구로 갈 수 있도록 하는 설정이 우선순위 설정이다. setPriority()를 사용해 우선순위를 할당할 수 있다. 
Thread 클래스의 필드에는 static final 필드인 MAX_PRIORITY, NORM_PRIORITY, MIN_PRIORITY가 있다. MAX의 값은 10, NORM의 값은 5, MIN의 값은 1이다. setPriority(Thread.MAX_PRIORITY);를 하면 해당 스레드의 우선순위는 MAX가 되는 것이다. 그러면 Runnable에서 가까운 입구로 들어가고 실행되어 다시 가까운 입구로 들어가기 때문에 자주 Run될 것이다. 

<<<pool>>>
뭔가 처리된 데이터들이 모여 있는 곳인 것 같다. 정렬되지 않고 모여 있는 곳 같다.