프로세스와 스레드
프로그램이 돌아가고 있는 상태를 프로세스라고 합니다.
예를 들어 바탕화면에 크롬을 선택하면 화면이 나옵니다. 화면이 나오는 상태를 프로세스라고 합니다. 크롬은 일을 할 때 게임을 다운받는 동시에 다른 페이지를 돌아다닐 수 있어야 합니다. 한 프로세스 안에도 여러 갈래의 작업들이 동시에 진행될 필요가 있습니다. 이 갈래를 스레드라고 합니다.
Context Switching
프로세스 1을 수행하다가 프로세스 2로 이동한다. 이를 Context Swithching이라고 합니다. 이동할 때 프로세스 컨트롤 블록에 프로세스 상태를 저장합니다. 문맥을 이어가기 위한 생태를 저장합니다. 연산할 때 상태가 변하는데 그 상태의 변화는 레지스터에 저장됩니다.
공유자원과 동기화
여러 프로세스, 여러 스레드가 동시에 한 자원에 접근할 수 있습니다. 한 동작을 위해 여러 개의 명령어가 실행될 수 있습니다. 중간에 무언가가 끼어들면 원자성이 보장되지 않아 결과가 생각한 방향과 멀어질 수 있습니다.
동시 접근시 원자성을 보장하기 위해 lock을 겁니다. 그리고 임계구간을 설정하여 관리합니다.
package hello.hellospring;
public class RamenProgram {
public static void main(String[] args) {
try{
RamenCook ramenCook = new RamenCook(50);
new Thread(ramenCook,"A").start();
new Thread(ramenCook,"B").start();
new Thread(ramenCook,"C").start();
new Thread(ramenCook,"D").start();
}catch(Exception e){
e.printStackTrace();
}
}
}
class RamenCook implements Runnable{
private int ramenCount;
private String[] burners = {"_","_","_","_"};
public RamenCook(int count){
this.ramenCount = count;
}
@Override
public void run() {
while(ramenCount>0){
synchronized (this){
ramenCount--;
System.out.println(
Thread.currentThread().getName()+":"+ramenCount+"개 남음"
);
}
for(int i=0;i<burners.length;i++){
if(!burners[i].equals("_")) continue;
synchronized (this){
burners[i] = Thread.currentThread().getName();
System.out.println(
" "
+Thread.currentThread().getName()
+(i+1)+"번 버너 ON");
showBurners();
}
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
synchronized (this){
burners[i] = "_";
System.out.println(Thread.currentThread().getName()+": "+(i+1)+"번 버너 off");
showBurners();
}
break;
}
try{
Thread.sleep(Math.round(1000*Math.random()));
}catch(Exception e){
e.printStackTrace();
}
}
}
private void showBurners(){
String stringToPrint = "";
for(int i=0;i<burners.length;i++){
stringToPrint +=(" "+burners[i]);
}
System.out.println(stringToPrint);
}
}
RamenProgram이라는 클래스안에 메인 메서드를 실행하고, RamenCook이라는 별도의 클래스를 넣었습니다.
RamenCook은 Runnable이라는 인터페이스를 사용하는데 Runnable의 run() 함수를 통해 스레드에서 진행할 작업을 정의합니다.
먼저 RamenCook이라는 객체를 만들때 생성자에서 라면의 갯수를 받아와서 RamenCount에 적용시킵니다.
라면 하나를 집어가서 ramenCount를 하나 줄입니다. 스레드 두개가 동시에 라면을 가져가면 실제로 2개가 주는데 카운트는 하나 줄 수 있으므로 이를 방지하기 위해 synchronized를 사용합니다. 이 안에 있는 변수들은 한 번에 한 스레드만 접근할 수 있습니다.
버너 4개 중 빈것을 찾습니다. 이 부분 역시 synchronized로 둘 이상의 스레드가 한 버너를 켜지 못하게 합니다. 여기서 버너들 상태를 showBurners()로 출력합니다.
스레드 sleep은 해당 스레드를 일정 시간 정지합니다. 라면을 끓는 시간을 정의하였습니다.
라면이 다 끓고 해당 버너를 비워야 합니다. 버너들 상태 여기서도 한번 출력하고 스레드마다 다음 라면을 끓이기까지 0초에서 1초까지 랜덤으로 시간이 걸리게 합니다. 이를 통해 순서를 어느정도 뒤엉키게 할 수 있습니다.
++
프로그램과 프로세스의 차이
프로세서보다 쓰레드가 문맥교환이 빠른 이유
Critical Section이 뭔가요?(임계구역) : 접근하면 큰일나는 공유 자원
동기화 기법 아는걸 설명해주세요: 세마포어, 뉴텍스
프로세서와 쓰레드의 차이는?
Context Switching은?
공유자원이란? 메모리관점, IO관점, 프로세스도 공유자원이 있다
'Java 특강' 카테고리의 다른 글
Java 코드가 실행되는 과정 (0) | 2024.10.01 |
---|---|
객체 지향이란 무엇인가요? (1) | 2024.09.26 |
오버라이딩이 내부에서 구현되는 법 (0) | 2024.05.10 |