임계영역
delay();
시간을 끄는거,, 끌다보면 다른 스레드가 가져갈거라 사용함.
T1 , T2, T3
스레드는 서로 간섭하지 않구 갈 길 감.
중간에 add()를 호출하면,,,
add 메서드안에서 cpu를 먼저 선점한 스레드가 시작하고 cpu 쟁탈전을 시작해서 작업시작.
T1이 cpu 뺏겼다해서 T2와 T3만 경쟁하는게 아니라 T1까지 동등한 입장에서 경쟁
Thread: 실행흐름
add: 코드, 메서드 호출될땐 stack에 로컬변수 생성됨.
각 스레드 별로 stack를 갖고 있음. 자기 실행흐름 진행을 stack에 담고있음.
로컬변수는 따로 관리함.
인스턴스는 공유함.
Critical Section = Critial Region (임계구역)
void add(int value) {
if(size >= values.length) {
return;
}
values[size] = value;
size = size + 1;
}
T1 (111) | T2 (222) | T3 (333) |
JVM Stack | JVM Stack | JVM tack |
value[111] | ||
Heap |
여러 스레드가 같은 메모리에 접근하여 값을 변경할 때 문제가 발생할 수 있다.
= > 이렇게 여러 스레드가 동시에 실행할 때 문제가 발생할 수 있는 코드블럭을... "Critical Section" 이라 부른다.
* 여러 스레드가 같은 메모리를 동시에 접근하더라도 단지 메모리의 값을 조회만 한다면 문제가 발생하지 않는다.
=> 이런 코드 블럭을 "Thread Safe" 스레드 안전이라 부른다.
해결책: synchronized
한 번에 한 스레드만 진입할 수 있다.
다른 스레드는 먼저 진입한 스레드가 메서드 호출을 마칠때까지 기다려야한다.
코드 블럭의 진입 개수를 제어하는 것을 : Semaphore (n)
semaphore(1) = mutex 뮤텍스: mutual Exclusion(상호 배제) ex) 선풍기 바람세기. 라디오 채널
자바는 뮤텍스만 지원한다. (semaphore(2이)가 안 된다는 뜻임 ;
순차적으로 실행한다는 것은 동시 실행의 이점을 버리는 것이기 때문에 스레드를 사용하기 전의 상태와 같다.
기존의 실행 방식 처럼 실행 시간이 많이 걸린다.
synchronized void add (int value) {
if (size >= values.length) {
return;
}
values[size]= value;
size = size +1;
}
=> 실행 완료된 스레드는 가비지가 된다.
=> 가비지 컬렉터가 가비지가 된 스레드를 수집하여 해제시키기 전까지는
그 스레드를 위해 할당된 메모리를 사용할 수 없다.
=> 즉 스레드를 매번 생성하는 방식은
과다한 가비지를 생성하기 때문에 메모리 낭비를 일으킨다.
스레드는 실제 OS가 생성한다. 즉 스레드를 생성하는데에 시간이 소요된다.
스레드 재사용 - 작업이 끝나면 대기상태로 만들어서 안 끝나게 만들기
wait() / notify()
-wait는 synchronized랑 같이 쓰여야함.
run에는 synchronized 붙이지 말기
wait()
- 해당 객체에서 notify()를 통해 알림이 올 때까지 스레드의 실행을 멈추게 한다.
- 이 메서드는 동기화 블록
(한 번에 한 스레드만이 진입하도록 설정된 블록)에서만 호출할 수 있다.
문법 주의!
=> wait()/notify() 는 반드시 동기화 영역 안에서 호출해야 한다.
동기화 영역?
=> synchronized로 선언된 메서드 예) synchronized void m() {}
=> synchronized로 묶인 블록 예) synchronized(접근대상) {...}
// 스레드 재사용 - 4단계) wait()/notify() 사용
package com.eomcs.concurrent.ex6;
import java.util.Scanner;
public class Exam0140 {
public static void main(String[] args) {
class ValueBox {
int count;
synchronized public void setCount(int count) {
this.count = count;
// 이 객체의 사용을 기다리는 스레드에게 작업을 시작할 것을 알린다.
//synchronized (this) {
this.notify();
//}
// 문법 주의!
// => notify()도 동기화 영역에서 호출해야 한다.
// => 안그러면 IllegalMonitorStateException 예외가 발생한다.
}
}
class MyThread extends Thread {
ValueBox valueBox;
public void setValueBox(ValueBox valueBox) {
this.valueBox = valueBox;
}
@Override
public void run() {
System.out.println("스레드 시작했음!");
try {
while (true) {
System.out.println("스레드 대기중...");
synchronized (valueBox) {
valueBox.wait();
}
System.out.println("카운트 시작!");
for (int i = valueBox.count; i > 0; i--) {
System.out.println("==> " + i);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ValueBox valueBox = new ValueBox();
MyThread t = new MyThread();
t.setValueBox(valueBox);
t.start(); // 이 스레드는 main 스레드가 실행하라고 신호를 줄 때까지 기다린다
Scanner keyScan = new Scanner(System.in);
while (true) {
System.out.print("카운트? ");
String str = keyScan.nextLine();
if (str.equals("quit")) {
break;
}
valueBox.setCount(Integer.parseInt(str));
// setCount()
// - 사용자가 입력한 카운트 값을 설정할 때
// - main 스레드는 이 객체의 사용을 간절히 기다리는 다른 스레드에게
// 즉시 사용하라고 신호를 보낸다.
// - setCount() 메서드의 코드를 확인해 보라!
}
System.out.println("main 스레드 종료!");
keyScan.close();
}
}
44. 스레드 재사용하기: 스레드풀(thread pool) 구현
스레드를 재사용하는 방법
GoF의 Flyweight 디자인 패턴을 적용하여 스레드풀을 구현하는 방법
1. 스레드풀 적용 전
클라이언트가 접속하면 서버앱에서 클라이언트 요청을 처리할 스레드를 생성한다.
클라이언트 응답을 완료하면 스레드는 가비지가 된다.
클라이언트 요청 수 만큼 스레드 생성, 가비지 생김, 시간낭비, 메모리 낭비
2. 스레드풀 적용 후
클라이언트1가 접속하면 서버앱이 스레드풀에서 get thread하고, 스레드풀은 스레드1 생성 후 리턴함.
클라이언트2가 접속하면 똑같이 작동 후 스레드2 리턴함.
3. 스레드 반납 Flywieght 패턴
C1이 T1 에 요청, T1 응답 후 T1이 스스로 Threadpool에 return Thread()함.
C2가 요청하면 T1 리턴해서 내줌
- 객체 사용 후 가비지를 버리지 않고 컬렉션에 보관.
- 객체가 필요할 때 컬렉션에 보관된 객체를 리턴함으로써 객체 재사용! => Flywieght 패턴- pooling 기법
=> 객체 생성 시간이 오래 걸리는 경우 (대표: 스레드 , 디비커넥션,)
=> 동일한 객체를 반복적으로 사용하는 경우
프로젝트
server- util 추가
다른 프로젝트에서도 사용하라고 껍데기들을 많이 만듬
'[네이버클라우드] 클라우드 기반의 개발자 과정 7기 > 웹프로그래밍' 카테고리의 다른 글
[NC7기-59일차(7월18일)] - 웹프로그래밍 40일차 (0) | 2023.07.18 |
---|---|
[NC7기-58일차(7월17일)] - 웹프로그래밍 39일차 (0) | 2023.07.17 |
[NC7기-56일차(7월13일)] - 웹프로그래밍 37일차 (0) | 2023.07.13 |
[NC7기-55일차(7월12일)] - 웹프로그래밍 36일차 (0) | 2023.07.12 |
[NC7기-54일차(7월11일)] - 웹프로그래밍 35일차 (0) | 2023.07.11 |