Skip to content

[4, 5단계 - 체스] 조엘(조영상) 미션 제출합니다.#236

Merged
seok-2-o merged 61 commits intowoowacourse:papimonlikelionfrom
joelonsw:step2
Apr 11, 2021
Merged

[4, 5단계 - 체스] 조엘(조영상) 미션 제출합니다.#236
seok-2-o merged 61 commits intowoowacourse:papimonlikelionfrom
joelonsw:step2

Conversation

@joelonsw
Copy link
Copy Markdown

@joelonsw joelonsw commented Apr 2, 2021

안녕하세요 미립! 우테코 3기 조엘입니다.
체스 미션 웹UI + DB 미션 진행해봤어요.

제가 이번 미션을 진행하면서 고민한 부분은 다음과 같아요

1. WEB UI 작업을 진행했어요
사실 HTML,CSS,JS를 해본적이 있어서 UI 만드는 것은 재미있었어요.
하지만 fetch API를 통한 JS 비동기 통신은 처음 적용해봐서 애를 먹었어요 😅
JS 투두리스트 미션 1,2 단계를 거치면서 개념을 잡았고, 이를 코드에 적용해봤어요.
최대한 Single Page Application을 만들기 위해 노력했고, 결과적으로 애정이 담긴 체스판이 탄생했어요 :)

2. SparkJava + Gson 을 적용했어요
자바 웹 프레임워크 중 하나인 SparkJava를 공부하고 적용해봤어요.
각 요청 URL에 따른 요청 처리 로직들을 구현했어요.
응답은 Gson 라이브러리를 사용해, DTO를 JSON으로 변환해 View단으로 넘겨줘요.
처음 써보는 프레임워크/라이브러리라서 내부 동작을 완벽히 이해하진 못하고 우선 돌아만 가도록 코드를 작성한 것 같아요...!

3. DTO와 DAO를 만들었어요
사실 이전 미션까지 DTO를 사용해본 적이 없었어요.
도메인 객체의 정보 중 다른 계층에 필요한 정보만 뽑아, 이를 객체화 시켜 넘겨주는 역할을 하는 클래스라고 개념만 알고 있었어요.
제대로 제가 DTO를 만들었는지 궁금합니다. 🤔
DAO라는 것도 처음 사용해봤어요.
DB에 저장하기 위해 DAO라는 것을 사용한다고 데이터베이스 기초 수업 시간에 배웠어요. 수업에 나온 코드를 기반으로, DB와의 커넥션을 적용해봤어요.
DAO 역시 똑바로 만들었는지 궁금합니다. 🤔

4. MySQL을 통해 DB를 적용했어요
사실 데이터베이스라는 것을 깊게 배워본 적이 없었어요.
쿼리도 처음 날려봤고, MySQL 세팅하는 것도 처음이었어요.
데이터베이스 기초 수업을 듣고, 필독서 SQL 첫걸음을 읽으면서 적용했던 것 같아요.
체스 게임에 사용한 테이블 구조는 README에 적어놨어요.

하나 고민했던 부분이 있어요.
DB에 접근하는 DAO CRUD 로직 중 update를 구현하지 않았어요.
move 명령으로 받은 기물의 예전 위치/현재 위치를 통해서 Update를 구현할 수 있겠다고 생각했어요. 현재 piece_position 테이블은 position을 Primary key로 들고 있거든요.
예전 위치를 통해 알맞은 piece_position row를 가져오고, 현재 위치로 해당 row를 업데이트 할 수 있겠다 생각했어요.
하지만 이러한 방식은 한 move에 두 가지 기물의 위치를 바꾸는 캐슬링이나,
move를 하면서 기물의 종류를 바꾸는 승격에 문제가 발생하리라 생각했어요.

따라서 현재, 저장 버튼을 누르면, 테이블의 정보를 모두 삭제하고 현재 진행중인 체스게임의 정보를 저장하는 방식을 채택했어요.
가장 큰 이유는 특별행마에 대한 DB 업데이트를 위해, 도메인의 객체들의 로직을 수정하고 싶진 않았어요.
또한 32개의 기물에 대한 정보만 저장하면 되니 DB 저장에 크게 병목이 발생하지 않을 것이라 생각했어요.

미립의 생각이 궁금합니다!

시연 영상
https://drive.google.com/file/d/158AZ1Io-vP1tkeG5EZ_hlgFxpX_QtByi/view

joelonsw added 30 commits March 28, 2021 23:47
@joelonsw
Copy link
Copy Markdown
Author

joelonsw commented Apr 6, 2021

안녕하세요 미립! 조엘입니다!
말씀해주신 피드백들을 바탕으로 리팩토링 진행해봤습니다 💪

[다음과 같은 리팩토링을 진행했어요]

1. DB 구조를 바꿨어요
https://github.com/PapimonLikelion/java-chess/tree/step2#readme
README 마지막에 테이블 구조를 작성해뒀어요.
기물 하나에 대해 team, piece, position, is_first_move를 각각 저장해 뒀던 기존 DB 설계에 반해, 이번에는 팀에 따라 기물 정보를 쫙 저장해 두어요.
image
이런식으로요.

특히 캐슬링, 프로모션의 특별행마들은 한 수에 두 가지 기물 위치가 바뀌거나, 기물의 종류가 바뀌게 되어요. 움직인 기물을 찾고, 어디로 움직였는지를 찾아, 이를 기존 DB에 적용하려면, 도메인의 수정이 불가피해요. (어쩌면 제가 도메인을 잘못 짠 걸 수도 있겠다 생각했어요.)

하지만 바뀐 DB 구조는 update 구현이 훨씬 수월했어요. 그저 이동 후 현재 체스게임의 화이트팀/블랙팀들의 Map<Position, Piece> 를 string으로 바꿔주어 저장만 하면 되어요.

또한 DB 연결의 시간도 줄 것이에요. 기존에 BlackTeam에 알맞는 체스 기물에 대한 정보를 DB에서 가져오려면, team='black'에 해당하는 ResultSet을 모두 돌면서 하나하나 기물을 생성해 줘야 했어요.

하지만 바뀐 DB는 한 번에 접근으로 black팀의 기물 정보들을 string으로 가져오고 이를 프로그램 안에서 parsing하여 기물을 생성하니, 성능 향상으로 이어지리라 생각이 들었어요.

19a341c
01c67be

2. Controller, Service, DAO를 Stateless하게 만들었어요
미립이 주신 피드백처럼, 해당 클래스들이 도메인에 관련된 인스턴스 변수를 갖지 않도록 했어요.
Service같은 경우, DAO를 통해 체스게임을 로드해와서 요청을 반영하는 형식으로 수정했어요.

Stateless한 객체는 multi-thread환경에서 thread-safe하다는 글을 읽었어요.
학교 운영체제 수업 때 race-condition에 대해 배운적이 있었는데, 그것과 관련되어 보였어요.
사실 아직 멀티 스레드 환경에서 작업해본 경험이 없어서 피부로 와닿지는 않아요.
우테코를 진행하면서 직접 제가 느껴볼 날이 있을 것 같아요!

하지만, 인스턴스 변수가 없으면 thread-safe하겠다는 것에는 수긍이 되어서 리팩토링 진행했습니다!
e75461a

3. HTTP 상태코드를 Enum으로 관리해요
이를 통해 프로그램의 가독성이 올라가고, 타입 안정성을 제공받을 수 있었어요.
자세한 것은 해당 링크에 작성했어요.
#236 (comment)

4. JDBC API의 자원을 해제해요
JDBC API에 대해 잘 몰랐어서 자원을 해제하는 코드를 작성하지 않았었어요.
체스 게임을 좀 많이 진행하다보면 DB에 이상하게 저장되는 것 같았는데 아마 그런 이유였던 것 같아요. 또한 MySQL Too many connections 에러를 만날 수도 있었어요.

현재 제 코드는 하나하나 connection, statement를 닫아 주도록 작성했어요.
현재는 코드량이 그렇게 많지 않아 명시적으로 닫아 줄 수 있으리라 생각했어요.
크루의 추천으로 try-with-resource에 대해서도 알아보았어요.
하지만 굳이 도입하지 않았어요. 명시적으로 닫아주는 연습도 해본 뒤에 해당 방법을 사용하고 싶었어요.

[다음과 같은 사안이 궁금해요]

1. 한 메서드에 동시에 요청이 오면?
동시 요청이 오면 어떻게 처리할 것 같냐는 미립의 질문에 제 나름대로의 생각을 작성해 두었어요. 하지만 솔직히 아직 잘 모르겠어요. 답변 부탁드릴게요!
#236 (comment)

읽어주셔서 감사합니다! 코로나 조심하세요 미립! 😥😥💪💪

Copy link
Copy Markdown

@seok-2-o seok-2-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피드백 반영 잘해주셨네요 :)
질문에 답변 및 추가적인 피드백 몇가지 남겨 놓았으니 확인 부탁드려요 :)

추가로 지금 데이터베이스에 기물정보를 한 컬럼에 모두 넣어놓고 파싱해서 사용하고 있어요.
RDB 는 말그대로 관계형(Relational)으로 구성되는게 좋다고 생각해요.
지금 단계에서 수정을 할 필요는 없다고 생각하지만 조엘도 한 번 가볍게 고민해보면 좋을 것 같아요.

return gson.toJson(DBConnectionDTO.fail());
} catch (IllegalArgumentException e) {
res.status(BAD_REQUEST.statusCode());
return gson.toJson(DBConnectionDTO.fail());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BAD_REQUEST.statusCode() 임에도 불구하고 DBConnectionDTO.fail()을 응답하고 있네요 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실수입니다... 우선 동작을 테스트하기 위해 임시로 적어놨던 것을 깜빡하고 수정하지 않았네요. 😭
다음과 같이 move에 대한 bad_request는 MoveResponseDTO로 응답을 처리하도록 변경했습니다!
376b610

Comment on lines +21 to +25
final String server = "localhost:13306"; // MySQL 서버 주소
final String database = "chess_db"; // MySQL DATABASE 이름
final String option = "?useSSL=false&serverTimezone=UTC";
final String userName = "root"; // MySQL 서버 아이디
final String password = "root"; // MySQL 서버 비밀번호
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상수로 관리해도 괜찮을 것 같은데 메소드 변수로 관리하는 이유가 있으신가요? 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상수로 관리하는 것이 가독성이 좋고, 메모리 상 접근 측면에서도 빠르다고 판단하여 상수로 변경했습니다!
c6ec39c

}

public synchronized ChessGameDTO startNewGame() throws SQLException {
chessGameDAO.deleteChessGame();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

게임이 진행중에 있는데, 다른 사람이 새로운 게임을 시작하면 기존게임이 삭제될 것 같아요 😱

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네! 삭제를 하고 재시작을 하더라도 최소한의 안내가 필요할 것 같아 다음과 같이 수정하였습니다.
40eb58f
8b23ec5

/forceNewGame이라는 API를 만들어서 현재 DB에 저장된 게임을 삭제하고 재시작 하는 옵션을 추가적으로 제공했습니다!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 이전에 말씀드린 동시에 여러 게임은

게임 1 은 저와 조엘이 게임을 진행하고
게임 2는 포비와 제이슨이 진행하는 것이 동시에 불가능할까? 라는 질문이였습니다.

해당부분에 대해서도 고민해주세요 :)

this.chessGameDAO = new ChessGameDAO();
}

public synchronized ChessGameDTO startNewGame() throws SQLException {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인스턴스 변수가 없는데 구지 synchronized 하게 만들어 줄 필요는 없을 것 같아요.
메소드가 실행되면 메소드에서 사용되는 변수는 독립적인 메모리영역에 로드되고 삭제될 것이에요
따라서 여러 메소드가 동시에 실행되어도 간섭을 받지 않아요.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오히려 synchronized 키워드 때문에 성능이 저하 될 수 있을 것 같아요.

Copy link
Copy Markdown
Author

@joelonsw joelonsw Apr 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

멀티 스레드 환경을 가정하고 생각을 했을때,
특정 스레드가 특정 메서드를 실행한다면,
각 스레드는 고유하게 스택을 가지고 있기 때문에,
각 스레드 고유 스택에 메서드에 필요한 변수/함수들이 적재되고 실행되고 없어질 것이에요.

현재 ChessService는 stateless하게 구현되어 있기 때문에,
다양한 스레드에서 작업을 실행해도 바뀔 인스턴스 변수가 없어요.

따라서 굳이 synchronized 예약어를 사용해 data의 thread-safe를 보장할 필요가 없어요.

다음과 같이 리팩토링 진행했습니다! 감사합니다 미립 :)
646ab21


public synchronized ChessGameDTO startNewGame() throws SQLException {
chessGameDAO.deleteChessGame();
final ChessGame chessGame = new ChessGame(Team.blackTeam(), Team.whiteTeam());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부에서 넣어줘야하는 파라미터인지 의문이네요.

Copy link
Copy Markdown
Author

@joelonsw joelonsw Apr 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createChessGame이라는 메서드 내부에서 ChessGame을 생성하고 DB에 저장하는게 훨씬 메서드 의미에 맞고 자연스럽네요!
다음과 같이 수정했습니다 감사합니다 :)
7036c22


public synchronized ChessGameDTO move(final String start, final String destination) throws SQLException {
final ChessGame chessGame = chessGameDAO.readChessGame();
System.out.println("chessGame = " + chessGame);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

소소하지만 System.out.println 로 찍는 출력들이 쌓이면 성능에 안좋은 영향을 미칠 수 있습니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 앞으로 주의하도록 하겠습니다! :)
518af82

final double whiteTeamScore = chessGame.calculateWhiteTeamScore();
final double blackTeamScore = chessGame.calculateBlackTeamScore();
final boolean isPlaying = chessGame.isPlaying();
return new ChessGameDTO(piecePositionToString, currentTurnTeam, whiteTeamScore, blackTeamScore, isPlaying);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이전 규칙에 메소드가 가지는 파라미터는 4개 이하로 유지하는 조건이 있는데 이를 지키도록 리펙토링 해보는건 어떤가요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네! 다음과 같이 수정완료하였습니다 :)
8cd680a

Comment on lines +7 to +8
private final String DTOFormat;
private final String DAOFormat;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동일한 정보를 다른 컨텍스트로 분리하신 이유가 궁금합니다 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 동일한 정보가 아니라고 생각했어요.
DTOFormat은 서버에서 팀에 대한 정보를 프론트단으로 넘겨줄 때, 팀을 어떠한 형식으로 넘겨줄지를 지정하고,
DAOFormat은 서버에서 팀에 대한 정보를 DB에 저장할 때, 팀을 어떠한 형식으로 저장할 지를 지정해요.

예를 들어 blackTeam을 프론트단에는 "black"으로 넘겨줘야하고, DB에는 "B"와 같은 형식으로 저장해야 한다면, 해당 클래스가 유용하리라 생각해요.

아직 DAO, DTO를 많이 접해보지 못해 확신은 없지만,
혹시나 매번 그 둘이 같은 정보를 같은 형식으로 표현하도록 코드를 작성해야 정석적인 것이라면, 해당 클래스는 굳이 필요가 없을 수도 있을 것 같아요.

@joelonsw
Copy link
Copy Markdown
Author

joelonsw commented Apr 8, 2021

안녕하세요 미립! 조엘입니다!!
말씀해 주신 피드백 바탕으로 리팩토링 진행했어요!
피드백을 거치면서 조금 더 코드의 의도가 명쾌해진 것 같아요. 감사해요 :)

[다음과 같은 리팩토링을 진행했어요]

1. ChessService의 메서드들의 synchronized 예약어를 삭제했어요.
synchronized 예약어는 멀티 스레드 환경에서 스레드간 동기화를 지원해요.
여러 개의 스레드가 한 개의 자원을 사용하고자 할 때, 현재 데이터를 사용하는 스레드를 제외하고는 나머지 스레드들의 접근을 막아줘요.

제가 처음 synchronized를 도입했던 이유는, ChessService에서 domain 객체를 인스턴스 변수로 가졌기 때문이에요. 멀티 쓰레드 환경에서 해당 domain 객체가 의도대로 동작하지 않는 것을 방지하고자 synchronized 예약어를 붙였어요.

하지만 리팩토링을 통해 ChessService가 domain 객체를 갖지 않도록 stateless하게 변환을 했어요. 따라서 다양한 스레드에서 ChessService 내의 메서드를 실행해도, race-condition이 발생할 인스턴스 변수가 없어요. 덕분에 stateless하게 구현하는 것의 장점을 느껴볼 수 있었습니다 :)

따라서 synchronized 예약어를 삭제했어요!

2. 진행 중인 게임이 있는 경우, 새로운 게임 요청을 받는다면?
DB에 완료되지 않은 게임 정보가 저장되어 있는데,
새로운 게임을 실행하도록 요청을 받는다면,
지금 까지는 그냥 기존 데이터를 모두 삭제하고 새로운 게임을 만들어 반환헀어요.

해당 방식을 다음과 같이 개선했어요.
만약 DB에 완료되지 않은 게임이 있는 상태에서 새로운 게임 시작 요청을 받으면,
사용자 UI에서 기존 게임을 삭제하고 새로운 게임을 시작하겠냐고 물어보게 만들었어요.

사용자가 새로운 게임을 시작하겠다라고 답변하면, forceNewGame 이라는 API로 요청을 보내 기존 게임 정보를 삭제하고 새로운 게임을 만들도록 했습니다.

하지만 해당 방식은 치명적인 약점이 있어요. 그냥 아무 사용자나 url에 /forceNewGame을 입력하면 기존 데이터는 사라지고 새로운 게임을 시작시킬 수 있을 것이에요. 프로를 위한 웹 기술 입문이라는 책을 읽고 있는데, 해당 문제는 유저를 생성하여 인가된 사용자에 한에 세션을 발급하면 해결할 수 있으리라 생각됩니다!

3. 미립이 남겨주신 피드백들을 반영했어요!
제 개인적인 실수들을 고쳤고, 메서드 이름에 알맞게 동작하도록 리팩토링 진행했습니다!
자세한 구현은 대댓글로 남겨놨어요!

[시연 링크]
https://drive.google.com/file/d/1tHu2R4Cs1oOozmyx87lBEaWzpUa1zKji/view?usp=sharing

@joelonsw
Copy link
Copy Markdown
Author

joelonsw commented Apr 8, 2021

Qs.
추가로 지금 데이터베이스에 기물정보를 한 컬럼에 모두 넣어놓고 파싱해서 사용하고 있어요.
RDB 는 말그대로 관계형(Relational)으로 구성되는게 좋다고 생각해요.
지금 단계에서 수정을 할 필요는 없다고 생각하지만 조엘도 한 번 가볍게 고민해보면 좋을 것 같아요.

Ans.
해당 방식으로 구현한 경우, 단점들에 대해 조사해봤어요.
다른 크루도 비슷한 피드백을 받아서, 이를 참고했어요.
참고: #260

1. 데이터에 대한 쿼리가 불가능해요
각 기물에 대한 정보만 빼오고 싶은 경우도 분명히 있을 거에요.
하지만 해당 방식은 이를 포기했어요.
이는 확장성이 떨어지는 방식이라고 판단이 되어요. ​

2. DB 마이그레이션이 어렵다
기존 데이터를 새로운 DB에 저장을 하려고 하는 경우,
그저 텍스트만 있는 현재 DB는 변화에 유연하지 못할 것 같아요.

@joelonsw
Copy link
Copy Markdown
Author

joelonsw commented Apr 10, 2021

사실 Web/DB 설계에 더 집중하는 것이 맞는 것 같지만, 1단계 필독서인 프로가 되기 위한 웹 기술 입문 이라는 책을 읽으면서 제 체스게임을 배포해보고 싶어졌어요.
자바를 인텔리제이에서만 사용했어서 콘솔에서도 사용해보고 싶었어요..!
삽질을 꽤 했지만 다행히 배포를 했습니다.

gradle 빌드 도구의 편안함을 느낄 수 있었고, 제 로컬에서만 사용했던 docker를 직접 서버 컴퓨터에서 실행해 보는 것도 좋은 공부라고 느꼈어요.

책에서는 Apache와 tomcat을 예시로 설명하는데, 저는 스파크자바에서 기본으로 제공하는 jetty 웹서버를 사용했어요.

웹 서버(Apache)와 웹 애플리케이션 서버(tomcat)에 대해 책에서 언급하는데 아직 웹 애플리케이션 서버에 대해 감이 잘 안잡혀요.
웹 서버는 HTTP 요청을 받아 정적 자원을 반환하는 것에 집중하고, 웹 애플리케이션은 동적인 페이지 생성을 위한 DB 연동등의 작업을 수행한다고 읽었어요. 하지만 웹 애플리케이션 서버와 웹 프레임워크의 차이를 아직은 잘 모르겠고요. 레벨 2에서 차차 공부해 나가면 될 것 같아요!

빌드 후, 서버에서 nohup sudo ./gradlew run 명령을 실행했어요.
sudo 권한으로 포트 80에 대한 바인딩을 할 수 있었고, nohup 명령어를 통해 백그라운드로 자바 메인함수를 실행하게 했어요.

http://ec2-3-36-97-77.ap-northeast-2.compute.amazonaws.com/

여기에서 체스게임을 해보실 수 있어요!

@joelonsw
Copy link
Copy Markdown
Author

학습로그

[Architecture] Service Layer

내용

  • Layer가 필요한 이유

    • Layer를 통해 역할을 추상화 할 수 있음
    • 다른 계층 끼리 부품을 갈아끼우듯 변환 가능
    • 컴포넌트들의 의존 계층 관계 유지 가능
  • Service Layer

    • 어플리케이션의 비즈니스 로직을 캡슐화하고, transaction을 조절하는 역할

링크

[JS] fetch API

내용

  • Ajax
    • 비동기 방식으로 데이터를 주고받는 JS 기술
    • 페이지 새로 고침 없이 서버에 요청하고, 응답을 받을 수 있음
  • fetch
    • Ajax 기술의 복잡도를 낮춰 사용할 수 있도록 fetch 보급
    • Promise를 반환함
      • 따라서, then() 메서드에 응답 처리하는 콜백함수 추가할 것

링크

[JDBC] 자원 반환

내용

  • Connection, Statement/PreparedStatement, ResultSet 들을 모두 close() 해줘야 한다
  • 그렇지 않다면...
    • Statement가 제대로 안 닫히면, 생성된 Statement의 갯수가 증가하여, 더 이상 Statement를 생성할 수 없게 됨
    • close() 하지 않으므로, 불필요한 자원을 낭비하게 됨 (네트워크/메모리)
    • 커넥션 풀을 사용하지 않는 상황에서 Connection 안 닫아주면 DBMS에 새로운 Connection을 만들 수 없음
  • 해결 방법으로 커넥션을 관리하는 class를 생성하거나, try-with-resource를 사용할 수 있다

링크

[Java] 멀티 스레드 환경에서 고려할 것

내용

  • 만약 인스턴스 변수가 있는 클래스에서 멀티 스레드 환경을 지원한다면, 해당 인스턴스 변수에 대해 쓰레드 동기화를 확보해야함
    • synchronized 예약어로 필요한 영역을 임계 영역으로 지정할 수 있음
    • 이렇게 된다면, 하나의 쓰레드만 접근/처리 가능하여 성능이 떨어질 것임
  • 만일 클래스를 stateless하게 만든다면, race-condition이 일어날 인스턴스 변수가 없다
    • 멀티 스레드 환경을 쉽게 지원할 수 있음

링크

Copy link
Copy Markdown

@seok-2-o seok-2-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

벌써 배포까지 진행하시다니 👍 👍
덕분에 체스도 한게임 진행해보았습니다 ㅎㅎㅎ

워낙 잘 해주신 덕분에 질문한가지 남겨놓고 이만 종료하도록 하겠습니다.
다음 미션도 잘 해내시라 믿고 응원하겠습니다.

저와의 미션은 종료되었지만, 앞으로도 궁금한점이나 어려운점 있다면 편하게 DM 주세요.

감사합니다. 🙇

@seok-2-o seok-2-o merged commit fb6d53c into woowacourse:papimonlikelion Apr 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants