무언가를 다운로드 받으려고 할 때 마우스가 움직이지 않는 등 다른 동작을 못하면 어떨까?
오늘 날과 같은 컴퓨터는 운영체제가 여러 개의 프로세스를 함께 돌리고 있기 때문임.
개념
Process
실행 중인 프로그램을 의미함. 즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말함. 이 프로세스는 프로그램에 사용되는 데이터, 메모리 등의 자원과 스레드로 구성됨.
Thread
스레드란 프로세스 내에서 실제로 작업을 수행하는 주체를 의미. 모든 프로세스에는 한 개 이상의 스레드가 존재. 한 개의 스레드를 가질 경우 싱글 스레드, 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드라고 함.
- 쉽게 말해 프로세스가 공장이라면 스레드는 실제 일을 하는 일꾼임.
- 비용 : 하나의 새로운 프로세스 생성 > 하나의 새로운 스레드 생성
- 공장 하나 당 일꾼이 들어가 일하는 것보다 하나의 공장에서 두 명의 일꾼이 일하는 것이 효율적인 것처럼.
- 장점 : 시스템 자원보다 효율적으로 사용 가능(카톡을 보내면서 영상을 봄), 사용자에 대한 응답성 향상, 작업이 분리되어 코드가 간결해짐.
- 단점 : 동기화(사건이나 시간을 같게 함), 교착상태(서로 필요로만 하는 상황), 각 스레드가 고르게 실행되는 등 프로그래밍 시 고려해야 할 사항이 많음.


*멀티 스레드의 경우 동일하게 실행되는 것 같지만 실제로는 알 수 없음.
*멀티 스레드가 싱글 스레드보다 시간이 더 걸림. context switch가 발생하기 때문.
구현과 실행
방법 ❶ Thread 클래스 상속
자바는 단일 상속만 가능하기 때문에 Thread 클래스를 상속받을 경우 다른 클래스 상속이 어렵기 때문에 잘 사용하지 않음.
방법 ❷ Runnable 인터페이스 구현
Runnable 클래스를 implements하기 때문에 extends는 여전히 가능하여 좀 더 유연하게 사용할 수 있음.
start()
- 스레드를 생성한 후에 start()를 호출해야 스레드가 작업을 시작함.
- OS 스케줄러가 실행순서를 결정, start했다고 즉시 실행되지 않음. 먼저 start했다고 먼저 시작되지 않음.
- start() 호출 → 새로운 run() 호출 → start() 역할 끝. run()은 main()과 독립적으로 생성, 수행됨.

예외 처리 - try catch
try문안의 수행할 문장들에서 예외가 발생하지 않는다면 catch문 다음의 문장들은 수행이 되지 않음. 하지만 try문안의 문장들을 수행 중 해당 예외가 발생하면 예외에 해당하는 catch문이 수행됨.

main 스레드와 상태제어 (join)
- 실행 중인 사용자 스레드가 하나도 없을 때 프로그램은 종료됨. 다만, run() 스레드 등 다른 스레드가 존재할 경우 main 스레드가 종료되어도 프로그램은 종료되지 않음.
- join()메소드는 스레드가 멈출 때까지 기다리게 함.
sleep, join 등 메소드 자체가 exception 을 throw 하는 메소드는 try, catch를 이용하여 예외처리를 해야 함.
우선순위
작업 중요도에 따라 스레드의 우선순위를 다르게 하여 특정 스레드가 더 많은 작업 시간을 갖게 할 수 있음.

- getPriority()와 setPriority() 메소드를 통해 스레드의 우선순위를 반환하거나 변경할 수 있음.
- 스레드의 우선순위는 1~10까지이며, 숫자가 높을수록 우선순위 또한 높아짐.
스레드의 우선순위는 비례적인 절댓값이 아닌 상대적인 값임. 무조건 우선순위가 높다고 더 빨리 끝나지 않음.
데몬 스레드
- 멀티태스킹 운영 체제에서 데몬은 사용자가 직접적으로 제어하지 않고, 백그라운드에서 돌면서 여러 작업을 하는 프로그램을 말함.
- 일반 스레드의 작업을 돕는 보조 역할 수행 (보조 스레드).
- 일반 스레드가 종료되면 자동으로 종료됨.
- ex) 가비지 컬렉터, 자동저장, 화면 자동갱신
사용법
- boolean isDaemon() - 스레드가 데몬 스레드라면 true를 반환.
- void setDaemon(boolean on) - 스레드로 데몬 스레드로 변경. 매개 변수 on을 true로 지정하면 데몬 스레드가 됨.
- setDaemon(boolean on)은 반드시 start()를 호출하기 전에 실행되어야 함.
인간과 컴퓨터
Counter와 Printer
스레드를 이용한 매수, 매도 프로그램
Seller와 Buyer 클래스를 스레드로 만들었다. 따라서 메인이 흘러가면서 동시에 매도, 매수가 이뤄지도록 했다
- 미해결 : 동기화 부분 해결하기
- 생성자 : 생성자란 인스턴스가 만들어질 때 호출되는 함수임.
생성자 이름은 클래스 이름과 일치해야 함. 또한 void와 같은 return 불가능.
- Synchronized : 여러 개의 스레드가 한 개의 자원을 사용하고자 할 때, 데이터를 사용하고 있는 스레드를 제외한 나머지 스레드들은 데이터에 접근 할 수 없도록 막는 역할.
한 시점에 오직 하나의 스레드만이 동기화된 인스턴스 메소드를 실행할 수 있음.
너무 남발하면 오히려 프로그램 성능 저하를 일으킬 수 있음.
- random.nextln() : 파라미터를 사용해서 원하는 범위 내의 양수 값을 가져올 수 있음.
마치며
스레드는 프로그램, 프로세스, 메모리 영역 등 컴퓨터와 관련된 내용이 많았다. 그래서 CS가 부족한 나에게 너무 힘든 과정이었다. 알면 알 수록 어려워지는 기분을 느꼈다. 질문을 하려 해도 내가 무엇을 모르는지 모르는 지경까지 도달해서 절망적이었다. 그래도 예시를 하나하나 다시 작성해보면서 감을 익혔다. 분명 이해했던 내용인데 코드로 다시 칠 땐 모르겠다. 그리고 생성자나 인스턴스 등 이미 공부했던 내용이 다시 헷갈렸다. 지금은 헷갈리는 게 덜한데 또 다른 코드를 치면 안 헷갈린다는 장담을 못 하겠다.