개발자입니다
[비트캠프] 63일차(13주차5일) - Java(네트워킹 연결방식, 스레드), myapp-33~35 본문
[비트캠프] 63일차(13주차5일) - Java(네트워킹 연결방식, 스레드), myapp-33~35
끈기JK 2023. 2. 3. 11:32
myapp
Networking 연결 방식
- Connection-Oriented (연결 지향)
예) 전화; WoW, LOL, 구글 미트, 웹메일
프로토콜 → TCP- Stateful 예) 상담 전화
프로토콜 : SSH, Telnet, FTP, 채팅
연결 → 요청, 응답 반복 → 끊기 - Stateless 예) 114 안내
프로토콜 : HTTP 1, HTTP 2
연결 → 요청, 응답 1번 → 끊기
- Stateful 예) 상담 전화
- Connectionless (비연결성)
예) 방송, 편지, 택배; ping
프로토콜 → UDP
Connection-Oriented : 연결하는 과정에서 시간을 소요, 연결한 후 데이터 전송 → 신뢰성 보장
Connectionless : 연결 과정이 없다 → 시간 절약, 연결 확인 없이 데이터 전송 → 신뢰성 낮다.
(TCP) HTTP 1/2 → (UDP) HTTP 3
Stateful 방식과 Stateless 방식 비교
-Stateful
요청과 응답을 반복한다.
뒤에서는 먼저 접속한 client가 연결을 끊을 때까지 대기.
한 클라이언트가 오랜 시간 연결되어 있으면 다른 클라이언트들의 대기 시간이 길어진다.
-Stateless
요청과 응답을 1번만 수행한다. 서버의 응답을 받으면 연결을 끊는다.
한 번 연결에 한 번의 요청/응답만 처리한다. 다른 클라이언트의 연결 대기 시간이 적다. 더 많은 클라이언트의 요청을 처리
33. Stateful → Stateless
### 33. 통신 방식을 Stateful에서 Stateless로 변경하기
- Stateful과 Stateless 방식의 차이점 이해
- Stateless 방식으로 통신하는 방법
NetworkBoardDao 에서 Server 로 ① 연결 ② 요청 하면 Server 에서 NetworkBoardDao 로 ③ 응답 한다. 그러면 NetworkBoardDao 에서 ④ 연결 종료 한다.
요청할 때마다 연결한다. 응답 후 연결 끊는다. 더 많은 클라이언트에 대응할 수 있다.
ServerApp 의 processRequest() 메서드에서 while 문을 제거한다.
public class ServerApp {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
processRequest(serverSocket.accept());
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
void processRequest(Socket socket) {
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
}
app-common 에 dao 패키지 생성 후 DaoStub 클래스 만든다.
Netwrok----Dao 에서 fetch 부분 가져온다.
public class DaoStub {
String ip;
int port;
public DaoStub(String ip, int port) {
this.ip = ip;
this.port = port;
}
public String fetch(String dataName, String action, Object... data)
throws DaoException {
try (Socket socket = new Socket(ip, port);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream())) {
out.writeUTF(dataName);
out.writeUTF(action);
if (data.length > 0) {
out.writeUTF(new Gson().toJson(data[0]));
}
// 응답
String status = in.readUTF();
if (status.equals("400")) {
throw new DaoException("클라이언트 요청 오류!");
} else if (status.equals("500")) {
throw new DaoException("서버 실행 오류!");
}
return in.readUTF();
} catch (DaoException e) {
throw e;
} catch (Exception e) {
throw new DaoException("오류 발생!", e);
}
}
}
app-common 의 dao 에 DaoException 옮겨온다.
ip, port 입력해서 DaoStub 생성 후 Network---Dao 생성시 주입한다.
public class ClientApp {
public static void main(String[] args) {
new ClientApp().execute("localhost", 8888);
}
void execute(String ip, int port) {
try {
DaoStub daoStub = new DaoStub(ip, port);
NetworkBoardDao boardDao = new NetworkBoardDao(daoStub);
NetworkStudentDao studentDao = new NetworkStudentDao(daoStub);
NetworkTeacherDao teacherDao = new NetworkTeacherDao(daoStub);
StudentHandler studentHandler = new StudentHandler("학생", studentDao);
TeacherHandler teacherHandler = new TeacherHandler("강사", teacherDao);
BoardHandler boardHandler = new BoardHandler("게시판", boardDao);
loop: while (true) {
System.out.println("1. 학생관리");
System.out.println("2. 강사관리");
System.out.println("3. 게시판");
System.out.println("9. 종료");
int menuNo;
try {
menuNo = Prompt.inputInt("메뉴> ");
} catch (Exception e) {
System.out.println("메뉴 번호가 옳지 않습니다!");
continue;
}
try {
switch (menuNo) {
case 1:
studentHandler.service();
break;
case 2:
teacherHandler.service();
break;
case 3:
boardHandler.service();
break;
case 9:
break loop; // loop 라벨이 붙은 while 문을 나간다.
default:
System.out.println("잘못된 메뉴 번호 입니다.");
}
} catch (Exception e) {
System.out.printf("명령 실행 중 오류 발생! - %s : %s\n",
e.getMessage(),
e.getClass().getSimpleName());
}
}
System.out.println("안녕히 가세요!");
Prompt.close();
} catch (Exception e) {
System.out.println("네트워킹 오류!");
e.printStackTrace();
}
}
}
NetworkBoardDao 에 DaoStub 변수 선언하고 생성자 아규먼트로 받는다.
Teacher, Student 도 동일하게 변경한다.
public class NetworkBoardDao implements BoardDao {
DaoStub daoStub;
public NetworkBoardDao(DaoStub daoStub) {
this.daoStub = daoStub;
}
@Override
public void insert(Board b) {
daoStub.fetch("board", "insert", b);
}
@Override
public Board[] findAll() {
return new Gson().fromJson(daoStub.fetch("board", "findAll"), Board[].class);
}
@Override
public Board findByNo(int no) {
return new Gson().fromJson(daoStub.fetch("board", "findByNo", no), Board.class);
}
@Override
public void update(Board b) {
daoStub.fetch("board", "update", b);
}
@Override
public boolean delete(Board b) {
daoStub.fetch("board", "delete", b);
return true;
}
}
34. 여러 클라이언트의 요청을 동시에 처리하는 방법
### 34. Thread를 이용한 멀티 태스킹 구현하기: 동시 요청 처리하기
- Thread로 멀티 태스킹을 구현하는 방법
- 멀티 태스킹의 이해
- 멀티 프로세스와 멀티 스레드의 구동 원리 이해
① 현재 상황
"main" 스레드가 클라이언트 요청을 순차적으로 처리한다.
② 멀티 스레드 적용
"main" 스레드가 접수받는 역할만 한다. Client1이 ① 접속 하면 스레드1 을 ② 생성 하면, 스레드1이 ③ 요청, ④ 응답을 처리한다. Client 2,3 도 마찬가지다.
여러 스레드를 동원하여 여러 클라이언트 요청을 "동시 처리"
Thread
스레드 생성 및 실행
① 서브 클래스 만들기
MyThread 가 Thread 를 상속한다. MyThread 객체 생성해서 t.start() 메서드 실행한다.
② 익명 클래스로 서브 클래스 만들기
Thread 객체 생성하고 익명 클래스로 서브클래스 바로 정의한다. 그리고 run() 메서드 정의한다. 뒤에 start() 메서드 실행한다.
③ Runnable 구현체 만들기
《interface》Runnable 을 구현한 MyRunnable 이 있다. Thread t 객체 생성하며 생성자 아규먼트에 Runnable 객체 전달한다. 그리고 t.start() 실행한다.
④ 익명 클래스로 Runnable 구현
Thread 객체 생성하며 생성자 아규먼트에 Runnable 객체 생성하고 익명 클래스로 서브클래스 바로 정의한다. 그리고 run() 메서드 구현한다. 뒤에 start() 메서드 실행한다.
public class ServerApp0 {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
new RequestProcessorThread(serverSocket.accept()).start(); // 스레드를 실행시킨다.
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
class RequestProcessorThread extends Thread {
Socket socket;
public RequestProcessorThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// 스레드를 통해 독립적으로 실행시키고 싶은 코드가 있다면
// run() 메서드 안에 두어라!
// 또는 run() 메서드에서 해당 코드를 호출하도록 만들어라!
//
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
}
}
public class ServerApp1 {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp1().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
Socket socket = serverSocket.accept();
new Thread() {
@Override
public void run() {
processRequest(socket);
};
}.start(); // 스레드를 실행시킨다.
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
void processRequest(Socket socket) {
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
}
public class ServerApp2 {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp2().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
Socket socket = serverSocket.accept();
new Thread(new RequestProcessor(socket)).start();
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
void processRequest(Socket socket) {
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
class RequestProcessor implements Runnable {
Socket socket;
public RequestProcessor(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
ServerApp2.this.processRequest(socket);
}
}
}
package bitcamp.myapp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
import bitcamp.myapp.dao.BoardDao;
import bitcamp.myapp.dao.StudentDao;
import bitcamp.myapp.dao.TeacherDao;
import bitcamp.myapp.servlet.BoardServlet;
import bitcamp.myapp.servlet.StudentServlet;
import bitcamp.myapp.servlet.TeacherServlet;
import bitcamp.myapp.vo.Board;
import bitcamp.myapp.vo.Student;
import bitcamp.myapp.vo.Teacher;
public class ServerApp3 {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp3().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
Socket socket = serverSocket.accept();
new Thread(new Runnable() {
@Override
public void run() {
processRequest(socket);
}
}).start();
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
void processRequest(Socket socket) {
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
}
public class ServerApp {
BoardDao boardDao = new BoardDao(new LinkedList<Board>());
StudentDao studentDao = new StudentDao(new ArrayList<Student>());
TeacherDao teacherDao = new TeacherDao(new ArrayList<Teacher>());
StudentServlet studentServlet = new StudentServlet(studentDao);
TeacherServlet teacherServlet = new TeacherServlet(teacherDao);
BoardServlet boardServlet = new BoardServlet(boardDao);
public static void main(String[] args) {
new ServerApp().service(8888);
System.out.println("서버 종료!");
}
void service(int port) {
System.out.println("서버 실행 중...");
try (ServerSocket serverSocket = new ServerSocket(port)) {
boardDao.load("board.json");
studentDao.load("student.json");
teacherDao.load("teacher.json");
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> processRequest(socket)).start();
}
} catch (Exception e) {
System.out.println("서버 오류 발생!");
e.printStackTrace();
}
}
void processRequest(Socket socket) {
try (Socket socket2 = socket;
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
InetAddress address = socket.getInetAddress();
System.out.printf("%s 가 연결함!\n", address.getHostAddress());
String dataName = in.readUTF();
switch (dataName) {
case "board":
boardServlet.service(in, out);
boardDao.save("board.json");
break;
case "student":
studentServlet.service(in, out);
studentDao.save("student.json");
break;
case "teacher":
teacherServlet.service(in, out);
teacherDao.save("teacher.json");
break;
}
} catch (Exception e) {
System.out.println("실행 오류!");
}
}
}
멀티 태스킹 (Multi-tasking)
① Single-tasking
CPU 가 App 을 실행하면 나머지 App 은 대기한다. 예) DOS
CPU 를 100% 활용 불가
사례1) 종업원이 손님1에게만 주문, 세팅, 서빙 한다.
한 번에 한 손님만 서비스 하면 손님1의 서비스가 끝날 때 까지 대기하므로 종업원(인력) 낭비!
사례2) 요리사에게 주문으로 짜장면1, 짬뽕1, 볶음밥1 이 들어오면 하나씩 요리한다.
① 짜장면을 다 만들고 나서 ② 짬뽕을 만들고 ③ 볶음밥을 만든다.
순차적으로 실행 → 주방장 월급이 아깝다.
② Multi-tasking
시간을 쪼개서 여러 App을 돌아다니면서 명령어를 실행 = 시분할 시스템
여러 App 이 동시 실행하는 것처럼 보인다. 예) Windows, Unix
사례1) 종업원이 손님1, 2, 3 에게 동시에 주문, 세팅, 서빙을 한다. 시간을 쪼개서 여러 손님을 응대
사례2) 요리사가 짜장면, 짬뽕, 볶음밥을 동시에 만든다. 시간을 쪼개서 여러 작업을 돌아가면서 실행
다중 클라이언트 요청 처리에 멀티 태스킹 적용
① 프로세스 복제 방식 (fork())
Client 1 이 Server 에 ① 접속하면 Server'로 ② fork (복제) 한다. 이 Server' 가 ③ 요청/응답 한다. Server 의 Heap, Stack 메모리를 복제한다.
Client 2 가 Server 에 ① 접속하면 Server''로 ② fork (복제) 한다. 이 Server'' 가 ③ 요청/응답 한다. Server 의 Heap, Stack 메모리를 복제한다.
Server 를 부모 프로세스, Server', Server'' 를 자식 프로세스라 한다.
문제점
① 프로세스(서버 프로그램)가 사용하는 메모리도 그대로 복제 → 메모리 낭비가 심하다.
② 부모 프로세스를 종료 하더라도 자식 프로세스는 종료되지 않는다. → 복제한 자식 프로세스를 제어하기 힘들다.
② 멀티스레드 방식
Client 1 이 Server 에 ① 접속 하면 ② 스레드 생성한다. 스레드가 ③ 요청/응답 한다. Server 의 Stack 메모리를 Thread에 복제한다. 이 메모리는 스레드가 작업하는 동안 사용할 메모리이다. Heap 메모리는 Server 와 공유한다.
Client 2 가 Server 에 ① 접속 하면 ② 스레드 생성한다. 스레드가 ③ 요청/응답 한다. Server 의 Stack 메모리를 Thread에 복제한다. 이 메모리는 스레드가 작업하는 동안 사용할 메모리이다. Heap 메모리는 Server 와 공유한다.
특징
① 프로세스의 Heap 메모리 공유 → 객체를 중복 생성하지 않는다 → 메모리 낭비가 적다
② 프로세스 종료 → 스레드 종료 → 스레드는 프로세스에 종속된다.
JVM 과 스레드
JVM (java.exe) 을 실행한다. JVM 은 프로세스이다. start() 하면 《Thread》main 이 실행된다. main 쓰레드가 main() 메서드를 call 한다. main() 에서 실행 되다가 다른 곳 갔다가 돌아오는 걸 반복하고 종료된다.
실행 흐름이 한 줄로 이어진 실타래와 같아서 "Thread"라 부른다!
부모 스레드와 자식 스레드
부모 스레드인 《Thread》main 에서 main() 메서드를 call 한다. main() 에서 new Thread() 하면 새 Thread (자식 스레드)가 생성된다. start() 하면 run() 메서드가 실행된다.
CPU Scheduling
프로세스에게 CPU 를 배정하는 방법
OS가 프로세스의 명령을 실행하는 순서나 시간을 제어한다.
① Round-Robin (Windows OS)
모든 프로세스를 동일한 시간으로 나눠 실행한다.
우선 순위가 실행에 영향을 덜 끼친다.
② Priority + Aging 기법 (Linux, Unix)
우선 순위가 높은 프로세스에게 실행 횟수나 시간을 더 부여한다.
우선 순위가 실해엥 영향을 끼친다.
CPU Scheduling 과 스레드
프로세스가 스레드 T1, T2, T3 를 생성한다.
OS 는 스레드에 대해서도 프로세스와 동일한 자격으로 스케줄링 한다.
프로세스가 받은 시간을 스레드가 나눠 사용하는 것이 아니다!
CPU 스케줄링과 Context Switching
Context Switching : 실행 정보와 명령을 CPU 캐시 메모리에 적재하는 것
CPU 안에 L1, L2 캐시가 있다. L1 에는 명령어, L2 에는 데이터를 저장한다.
프로세스 A, B, C, ... 가 있고 OS 가 A 를 ① 실행 하면 ② 캐시메모리에 적재 한다. B 를 ③ 실행 하면 캐시메모리에 ④ 적재 한다. 기존 프로세스 실행정보는 캐시메모리에 보관된다.
Context Switching
CPU 스케줄링 정책에 따라 프로세스를 돌아가면서 실행할 때, 이전 프로세스의 실행 정보를 보관 → 다른 프로세스의 실행 정보를 적재한다.
너무 짧은 시간동안 너무 자주 프로세스를 교체하면 명령을 실행하는 시간보다 Context Switching 시간이 더 많이 소요되기 때문에 비효율적이 된다. 그래서 적절한 시간에 따라 프로세스를 교체해야 한다.
Critical Region = Critical Section
여러 스레드가 동시에 실행할 때 문제가 발생할 수 있는 코드 영역 → synchronized 를 사용하여 동시 진입을 제어한다.
Critical Section : 여러 사람이 동시에 진입할 때 문제 발생! Semaphore(1) = "Mutex"
Critical Section : Semaphore(5) *Semaphore: 동시진입 제어하는 것
Mutual Exclusion (상호 배제)
3개 중에 오직 1단계만 선택 가능. 한 개 선택하면 다른 단계는 취소된다.
예) 라디오 채널, TV 채널
Mutex → 오직 한 개만 선택!
조언
*현업 하고 나서 컴공과 수업 들으면 와닿는다. 개발 업무 하면서 네트워킹 책 보면서 바닥을 다져야 한다. 유닉스의 탄생 책 꼭 봐라.
*분석 설계자는 코드를 한 줄씩 바라보는게 아니라, 객체를 사람으로 보고 메서드를 명령으로 본다. 예) daoStub 한테 fetch 시
과제
학습
-com.eomcs.concurrent
'네이버클라우드 AIaaS 개발자 양성과정 1기 > Java' 카테고리의 다른 글
[Java] 예제 소스 정리 - 스레드 (0) | 2023.02.04 |
---|---|
[Java] 예제 소스 정리 - 네트워킹(HTTP, 연결 방식) (0) | 2023.02.03 |
[Java] 예제 소스 정리 - 네트워킹(Client/Server, 연결 방식) (0) | 2023.02.02 |
[비트캠프] 62일차(13주차4일) - Java(Client, Server 아키텍처), myapp-32-1~2 (0) | 2023.02.02 |
[비트캠프] 61일차(13주차3일) - Java(네트워킹), myapp-29~32 (0) | 2023.02.01 |