Java Stream, Thread

Java의 Thread 기본 개념과 동시성 해결, Stream의 종류 및 객체 입출력 방식에 대해 설명합니다.

<2019년 7월 9일>

 

[Thread]

- 프로세스 : 일련의 작업의 단위

- 쓰레드    : 프로세스 내에 기생하는 작업 일부의 단위

- 자바에서는 Thread 클래스를 상속받거나, Runnable 인터페이스를 구현하는 방식으로 쓰레드를 구현할 수 있다. 주로 Runnable 인터페이스를 구현한다.

- Runnable 인터페이서에서는 run() 을 오버라이드에서 실행하고, Thread 클래스에서는 start() 를 오버라이드해서 쓰레드를 구현한다.

- synchronized 를 통해 주어진 변수에 대한 잠금장치(?) 를 설정할 수 있다. (method 에 synchronize 를 설정하는 것이 나을 것인가? 아니면 매소든 내의 블록을 synchronized 로 설정하는게 나을 것인지는 판단해야 한다.) -> 동시성 해결

- 스레드 제어 메서드를 잘 이용하는 것이 중요하다. run(), sleep() ...

 

* 쓰레드의 life cycle

쓰레드 객체 생성 -> start() -> Runnable(실행 대기) -> 

실행 대기 상태에서, run() 이 콜백되게 된다. CPU 는 타임 슬라이스 방식으로 각 쓰레드마다 일정 시간만을 할당해 준다. 시간이 끝나게 되면 다시 작업 대기열에 들어가 있다가 선택받으면 업무를 수행한다.

sleep(), join(), wait(), notify(), notifyAll(), interrupt() 중지

 

package com.sinc.thread;



import com.sinc.thread.shared.SharedObj;



public class PrtThread implements Runnable {


    private char charValue;
    private SharedObj moniter;

    

    public PrtThread() {}
    public PrtThread(char charValue, SharedObj moniter) {

        this.charValue = charValue;
        this.moniter = moniter;

    }

    

    @Override
    public void run() {
        synchronized(moniter) {


            /*

             * 선행되어야 하는 proc 이 있는데, 실행되지 않았을 경우 wait 시킨다. 

             * 선행되는 proc 이 완료된 후에는, notify() 를 호출해야 한다.

             * 깨워야 하는 쓰레드가 많을 경우에는, notifyAll() 을 실행해야 한다.

             */

           
            for(int i = 0 ; i < 10 ; i++) {
                this.moniter.printChar(charValue);
            }
        }
    }
}


package com.sinc.thread.shared;


public class SharedObj {
    public synchronized void printChar(char value) {
        for(int i = 0 ; i < 10 ; i++) {
            System.out.print(value);
        }
        System.out.println();
    }
}

 

 

[Stream]

Stream 은 Byte 단위로 입출력을 처리하는 방식이 있고(1바이트로 입력을 받는다. 한글은 2바이트이므로 입력받을수 없다.), char 단위로 입력을 담당하는 방식이 있다.

java.io.* 안에 Stream 패키지가 있다.

 

- Byte 단위의 Stream : xxxStream 의 방식의 이름으로 이루어져 있다.

- Char 단위의 Stream : xxxReader/Writer 의 방식으로 이름이 이루어져 있다.

(Scanner 의 경우, 1바이트를 2바이트로 변환시켜 주는 기능이 내장되어 있다.)

- xxxReader 는 xxxStream 을 매개변수로 받을 수 있다.

- 대부분의 경우, 하나의 Stream 은 read / write 둘 중 하나만 수행하게 된다.

- Stream 과 관련된 함수들은 모두 예외를 throw 한다. 유저는 이를 예외처리 해주어야 한다.

 

* 통신하는 과정에서, Object 를 어떻게 다른 클라이언트에 넘길 수 있을까 ?

- Serializable 이라는 인터페이스를 구현하고 있어야 한다. byte Stream 에서 ObjectInput / ObjectOutput으로 시작하는 객체만 구현하면 된다.

- 나의 PC 에 있는 주소 번지 객체를 넘긴다고 해서 다른 PC 에서 이해할 수 있을까 ? 불가능하다. 객체를 그대로 넘겨줄 수는 없지만, 객체를 ByteStream 으로 바꾸어서 다른 클라이언트에 넘겨주게 된다.

- Serializable 인터페이스는 추상 매서드를 구현하고 있지 않은 인터페이스이다. (이러한 인터페이스를 마킹 인터페이스라고 한다.)

- Collections 는 Serialiazable 을 구현하고 있기 때문에, 객체 형식으로 데이터를 주고받는 것이 가능하다.

- String 은 Serialiazable 을 구현하고 있기 때문에, 객체 형식으로 데이터를 주고받는 것이 가능하다.

 

package com.sinc.stream;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

// char 단위로 output 을 하기 위해 사용한다.
import java.io.FileWriter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class StreamObj {

    public void saveToFile() {
        File             file   = null;
        FileWriter          writer = null;
        BufferedWriter     buffer = null;
        
        //// Object Stream (직렬화 된 데이터를 보내기 위해선 byte 단위로 보내야 하기 때문에, reader / writer 을 활용할 수 없다.)

        FileOutputStream    fos    = null;
        ObjectOutputStream     oos = null;
        
        try {
            // FileWriter
            file     = new File("./text.txt");
            writer    = new FileWriter(file);
            // writer 은 2차선, buffer 은 8차선
            // writer.write("2바이트 크기로 write 가능");
            buffer    = new BufferedWriter(writer);
            buffer.write("테스트 입니다.");

            // ObjectOutput

            file     = new File("./obj.txt");
            fos        = new FileOutputStream(file);
            oos        = new ObjectOutputStream(fos);
            List<String> list = new ArrayList<>();
            list.add("one"); list.add("two"); list.add("한글");
            oos.writeObject(list);
            System.out.println("buffer close");

        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            try {

                if(buffer != null) {
                    buffer.close();
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void loadToFile() {

        FileInputStream      fis = null;
        ObjectInputStream     ois = null;

        try {

            fis        = new FileInputStream("./obj.txt");
            ois        = new ObjectInputStream(fis);
            List<String> list = (List)(ois.readObject());
            System.out.println(list);

        } catch(Exception e) {
            e.printStackTrace();
        } finally {

            try {

            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 


이것도 읽어보세요