
아주 짧은 시간(=quantum)만 CPU에서 실행되도록 하자
응답 시간을 최소화 시키는데 목적컨텍스트 스위칭은 무거움컨텍스트 스위칭이란 cpu 실행되기 위해 어느 한 프로세스에서 다른 프로세스로 교체되는 것듀얼 코어가 등장했는데 잘 쓰고 싶음같은 프로세스의 스레드들끼리 컨텍스트 스위칭은 가볍다.💡 파란색과 녹색은 스레드들이 속한 메모리 영역


같은 프로세스를 가진 스레드들은 같은 메모리 공간을 공유하되, 스레드들 만의 고유한 영역도 있다.
- 스레드가 등장하고 난 뒤 메모리 구조
힙 메모리 영역을 공유- 자신의 고유한 영역이 바로
스택- 각각의 스레드마다 프로그램 카운터들이 따로 있음
- 프로그램 카운터 : 다음번에 실행돼야 할 명령어가 있는 메모리 주소를 가짐

코드의 재사용성이 높아지고 유연성이 높아지기 때문에 상속보다 좋
public class MyThread implements Runnable {
@Override
public void run(){
// 수행 코드.
}
}
Runnable 인터페이스를 구현하는 방법은 다른 클래스를 상속받을 수 있다.run() 메소드를 오버라이딩하여 스레드가 수행할 작업을 정의start() 메소드가 없으므로, 실행하기 위해서는 Thread 객체를 생성하고 생성자에 Runnable 구현 클래스의 인스턴스를 넘겨주어야 한다.⇒ Thread 클래스 내부에서 run 메서드를 호출하는 것이 아니라, 전달된 Runnable 객체의 run 메서드를 호출
public static void main(String[] args){
Runnable runnable = new MyThread(); //MyThread는 Runnable 구
Thread t = new Thread(runnable, "mythread");
}
thread 클래스를 상속받아서 run 메서드를 오버라이딩하여 스레드가 실행할 코드 작성
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}
public class MyThread extends Thread {
@Override
public void run() {
// 스레드가 실행할 코드 작성 => run 메서드 재정의
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getId() + " Value " + i);
}
}
}
currentThread()를 호출해 현재 스레드에 대한 참조를 얻어와야만 호출이 가능하다.Thread.currentThread().getId()는 현재실행 중인 스레드의 고유한 식별자로 스레드가 생성될 때 자동으로 할당되는 값으로, 서로 다른 스레드는 다른 ID를 가지게된다.스레드의 실행은 run() 호출이 아닌
start()호출로 해야 한다.
우리가 정의했던 메소드는 run()이지만, 실제로 스레드에 작업을 시키려면 start()로 작업해야 하는데 그 이유는 run() 메소드를 사용한다면, 이건 스레드를 사용하는 것이 아니다.
자바에는 Call Stack 이라는 것이 있는 데, 이 영역이 실질적인 명령어들을 담고 있는 메모리로, 하나씩 꺼내서 실행하는 역할을 한다.

)
🔗 사진 출처 : https://medium.com/swlh/in-depth-introduction-to-call-stack-in-javascript-a07b8513bcc3
만약 동시에 두 가지 작업을 한다면, 두 개 이상의 Call Stack이 필요하게 된다.
즉, 스레드를 이용한다는 것은
JVM이 다수의 Call Stack를 번갈아가면서 일처리를 하고 사용자에게는 동시에 작업을 한다는 것처럼 보여주는 것이다.
그렇기 때문에 run() 메소드를 이용한다는 것은 main()의 콜 스택 하나만 이용하는 것으로 스레드 활용이 아니다. (그냥 스레드 객체의 run이라는 메소드를 호출하는 것 뿐이게 된다.)
start() 메소드를 호출하면 JVM은 알아서 스레드를 위한 콜 스택을 새롭게 만들어주고 context switching을 통해 스레드답게 동작하도록 해준다.
결국, 우리는 새로운 콜 스택을 만들어 작업을 해야 스레드 일처리가 되는 것이기 때문에 start() 메소드를 써야 하는 것이다.
start()는 스레드가 작업을 실행하는 데 필요한 콜 스택을 생성한 다음run()을 호출해서 그 스택 안에 run()을 저장할 수 있도록 해준다.

🔗 사진 출처 : https://velog.io/@sugyeonghh/section-1-Java-심화2-스레드
스레드를 사용하는 것이 효율적이라 하지만, 어렵다.
이유는 위와 같이 다양한 상태를 가지고 있으며, 이를 잘 사용하기 위해선 동기화와 스케줄링이 필요하기 때문이다.
멀티 스레드 프로세스의 경우, 같은 데이터에 동시에 공유하는 경우 발생
➡️ 데이터의 오류❗️
➡️ 한 스레드가 사용할 때 접근하지 못하도록 임계영역 필요
✔️ 임계영역 Critical Section
오직 하나의 스레드만 코드를 실행할 수 있는 코드 영역
synchronized키워드로 임계 영역을 지정
✔️ 락 Lock
임계 영역을 포함하고 있는 객체에 접근할 수 있는 권한
임의의 스레드 A가 임계 영역 코드를 실행할 경우 A는 락을 갖게 되고, 다른 스레드들은 락이 없어서 임계 영역 코드를 실행할 수 없음!
멀티스레딩 환경에서 쓰는 것을 말함
더 작은 작업들로 잘게 쪼개서 동시에 실행이 가능한 성격의 애플리케이션순차적으로 실행되어야 하는 애플리케이션이라면.. 그래서 잘게 쪼개서 동시에 실행하기 매우 어려운 성격의 애플리케이션이라면 스레드를 많이 쓰려고 해도 실제 사용할 수 있는 스레드 수는 제한이 생김context switching을 하는데, 이런 스위칭 작업도 CPU 코어에서 실행되게 되는 작업스위칭 작업을 처리하는 동안에는 애플리케이션 코드가 실행되지 않음overhead : 이때, 스위칭 작업을 위해 소비되는 CPU time은 애플리케이션과 직접적인 관련은 없지만 멀티스레딩으로 동작하기 위해 필요하기 때문에 간접 방식이라고 부름