프로세스 (Process): 운영체제(OS)로부터 자원(메모리, CPU)을 할당받아 실행 중인 프로그램의 단위. 각 프로세스는 독립적인 메모리 공간을 가집니다. (e.g., Chrome 브라우저, IntelliJ IDEA)
스레드 (Thread): 프로세스 내에서 작업을 수행하는 실행 흐름의 단위. 하나의 프로세스는 하나 이상의 스레드를 가질 수 있으며, 같은 프로세스 내의 스레드들은 메모리 자원을 공유합니다.
멀티태스킹 (Multi-tasking): 여러 개의 프로세스가 동시에 실행되는 것.
멀티스레딩 (Multi-threading): 하나의 프로세스 내에서 여러 개의 스레드가 동시에 실행되는 것.
Thread 클래스 상속java.lang.Thread 클래스를 상속받는 새로운 클래스를 만듭니다.
run() 메서드를 오버라이딩하여, 해당 스레드가 수행할 작업을 작성합니다.
start() 메서드를 호출하여 스레드를 실행합니다. (run()을 직접 호출하면 안 됨!)
class MyThread extends Thread {
@Override
public void run() {
System.out.println("새로운 스레드가 실행됩니다.");
}
}
// 실행
MyThread t = new MyThread();
t.start(); // OS에 스레드 생성을 요청하고, run() 메서드가 실행됨
Runnable 인터페이스 구현 (권장)java.lang.Runnable 인터페이스를 구현하는 클래스를 만듭니다.
run() 메서드를 구현하여 스레드가 수행할 작업을 작성합니다.
Thread 클래스의 생성자에 Runnable 구현 객체를 전달하여 Thread 객체를 생성합니다.
start() 메서드를 호출하여 스레드를 실행합니다.
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable을 이용한 스레드가 실행됩니다.");
}
}
// 실행
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
// 람다 표현식으로 더 간결하게
new Thread(() -> System.out.println("람다를 이용한 스레드")).start();
Runnable 구현이 더 권장되는가?: Java는 다중 상속을 지원하지 않으므로, Thread 클래스를 상속하면 다른 클래스를 상속할 수 없게 됩니다. Runnable 인터페이스를 구현하면 이러한 제약에서 자유로워져 더 유연한 설계가 가능합니다.synchronized 키워드synchronized 메서드: 메서드 전체를 임계 영역으로 지정합니다. 이 메서드는 한 번에 하나의 스레드만 실행할 수 있습니다.
synchronized 블록: 특정 객체(lock)에 대한 잠금(lock)을 획득한 스레드만 해당 코드 블록을 실행할 수 있도록 합니다. 메서드 전체가 아닌, 꼭 필요한 부분만 동기화하여 성능을 높일 수 있습니다.
public class BankAccount {
private int balance;
private final Object lock = new Object();
// synchronized 블록을 이용한 동기화
public void deposit(int amount) {
synchronized (lock) {
balance += amount;
}
}
}
| 구분 | 바이트 스트림 (Byte Stream) | 문자 스트림 (Character Stream) |
|---|---|---|
| 단위 | 1 byte | 2 bytes (char) |
| 최상위 클래스 | InputStream / OutputStream | Reader / Writer |
| 주요 용도 | 이미지, 동영상, 실행 파일 등 모든 종류의 바이너리 데이터 | 텍스트 데이터 (문자 인코딩 자동 처리) |
| 하위 클래스 예시 | FileInputStream, FileOutputStream | FileReader, FileWriter |
FileInputStream)에 추가적인 기능을 덧붙여주는 스트림입니다. (데코레이터 패턴)BufferedInputStream / BufferedReader: 내부에 버퍼(buffer)를 두어, 데이터를 한 번에 많이 읽어와 I/O 성능을 크게 향상시킵니다.InputStreamReader / OutputStreamWriter: 바이트 스트림을 문자 스트림으로, 또는 그 반대로 변환해주는 "다리" 역할을 합니다.try-with-resources)Java 7부터 도입된 try-with-resources 구문을 사용하면, finally 블록에서 close()를 명시적으로 호출하지 않아도 스트림이 자동으로 닫혀 코드가 매우 간결해집니다.
// 파일에서 한 줄씩 텍스트 읽기
String filePath = "myFile.txt";
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
Runnable 인터페이스 구현 방식이 권장됩니다.synchronized 키워드를 사용하여 동기화 처리를 해야 합니다.BufferedReader 등)을 사용하여 I/O 성능을 향상시킬 수 있으며, try-with-resources 구문을 통해 리소스를 안전하고 간결하게 관리해야 합니다.