프로세스는 간략하게 말하면 실행 중인 프로그램이다. OS로부터 실행에 필요한 자원을 할당받는다. 프로그램을 수행하는데 필요한 데이터와 메모리 등의 자원 그리고 쓰레드로 구성되어 있다.
이미지 출처 - https://velog.io/@p1atina/자바의-정석-프로세스와-쓰레드
쓰레드는 프로세스가 운영체제로부터 할당받은 자원들을 이용해서 작업을 수행하는 것을 말한다.
프로세스는 작업공간, 쓰레드는 일꾼이라 했을 때 프로세스라는 작업공간에서 작업을 처리하는 일꾼으로 비유하면 조금은 쉽게 생각할 수 있을 것이다.
모든 프로세스에는 최소한 하나의 쓰레드를 가지고 있고, 둘 이상의 쓰레드를 가진 프로세스도 있는데 이것을 멀티쓰레드 프로세스라고 한다.
하나의 프로세스가 가질 수 있는 쓰레드는 제한이 없지만 쓰레드가 작업을 수행하는데 개별적인 메모리 공간(호출스택)을 필요로 하기 때문에 프로세스의 메모리 한계에 따라 생성할 수 있는 쓰레드의 수가 결정된다.
윈도우나 유닉스 같은 OS는 멀티태스킹을 지원한다. 그래서 여러 개의 프로세스가 동시에 실행될 수 있다. 비슷한 맥락으로 멀티쓰레딩은 하나의 프로세스에 여러 개의 쓰레드가 동시에 작업을 수행하는 것이다. 여러 개의 쓰레드들이 아주 짧은 시간 동안 여러 작업을 번갈아 가며 수행함으로써 여러 작업들을 모두 동시에 수행하는 것처럼 보이게 한다. 그래서 우리가 크롬도 여러 개 활성화 하면서 파일도 다운받고 이외에 다른 작업들도 할 수 있는 것이다.
프로세스의 성능이 쓰레드가 많다고 해서 꼭 좋은 것은 아니며 오히려 여러 개의 쓰레드보다 하나의 쓰레드가 성능이 더 나을수도 있다.
단점
같은 프로세스 내에서 여러 쓰레드들이 서로 자원을 공유하면서 작업을 하기 때문에 발생할 수 있는 동기화, 교착상태와 같은 문제들을 고려해서 신중히 프로그래밍 해야 한다.
public class ThreadEx1 {
public static void main(String[] args) {
ThreadEx1_1 t1 = new ThreadEx1_1();
Runnable r = new ThreadEx1_2();
Thread t2 = new Thread(r); // 생성자 Thread(Runnable target)
t1.start();
t2.start();
}
}
class ThreadEx1_1 extends Thread {
public void run() {
for(int i = 0; i < 5; i++){
System.out.println("extends Thread " + getName()); // 조상인 Thread의 getName()을 호출
}
}
}
class ThreadEx1_2 implements Runnable {
public void run() {
for(int i = 0; i < 5; i++){
// Thread.currentThread() - 현재 실행중인 Thread를 반환한다.
System.out.println("implements Runnable " + Thread.currentThread().getName());
}
}
}
쓰레드를 구현하는 방법이 두 가지가 있는데 Thread클래스 상속과 Runnable인터페이스로 구현을 한 코드이다. 일반적으로는 Runnable인터페이스를 구현하는 방법을 선택한다. Thread클래스는 상속받으면 다른 클래스를 상속받을 수 없기 때문에 객체지향적인 방법으로 Runnable인터페이스로 구현을 하여 재사용성과 코드의 일관성을 유지할 수 있기 때문이다.
Thread클래스로 생성한 인스턴스의 경우에는 Runnable로 구현한 인스턴스를 생성자의 매개변수로 제공해야 한다. Thread클래스 API를 확인해보면 Runnable타입 변수를 선언하고 생성자를 통해서 Runnable인터페이스를 구현한 인스턴스를 참조하도록 되어 있는 것을 확인할 수 있다. 이와 같이 Thread클래스로 구현을 하면 오버라이딩을 하지 않고 run()을 제공받을 수 있다.