์ ๋๋ฒ์ค์คํ
์ด(์๋ฐ์์ฝ ํ๋ซํผ) ํ๋ก์ ํธ๋ฅผ ๊ตฌ์ถํ๋ฉด์, ๊ธฐ๋ฅ ๊ตฌํ์๋ง ์ฐ์ ์์๋ฅผ ๋์์๋๋ฐ ๋์์ฑ ๋ฌธ์
์ ๋ํ ํผ๋๋ฐฑ์ ๋ฐ์์๋ค.
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ๋ช
์๋ค๊ณ ๊ฐ์ ํ์๋, ์ฌ์ฉ์(๊ฒ์คํธ)๊ฐ ๊ฐ์ ๋ ์ง ํน์ ๊ฒน์น๋ ๋ ์ง์ ๋์์ ์์ฝ์ ํ๋ค๋ฉด
์ด๋ป๊ฒ ๋ ๊น?
์ฐ์ ์ ๋ง ์์ด์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก ํ ์คํธํด๋ณด๊ธฐ ์ํด์ ๋์๋์ ์๋ฒ์์ ํ์ ํ๋ช ๊ณผ ํจ๊ป ๋์์ ์์ฝ ์์ฒญ์ ํด๋ดค๋ค๐คฃ
๊ทธ๋ฌ๋๋.. ๋ช๋ฒ ์๋ํ์ ๋ ์ ๋ง ๋์์ ๊ฐ์ ๋ ์ง๋ก ์์ฝ์ด ๋๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค ๐
ํ
์คํธ์ฝ๋๋ก ์ฐ๋ ๋๋ฅผ ์ฌ๋ฌ๊ฐ ๋๋ฆฐ๊ฒ ์๋ ์ธ๊ฐ์ ์์ผ๋ก ๋์์ฑ์ ์ฒดํฌํ๋๋ฐ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ฉด, ์ค์ ์๋น์ค์์๋ ๋ฌด์กฐ๊ฑด ์์ฒญ๋ ๋ฌธ์ ๊ฐ ์๊ธธ๊ฒ ๋ถ๋ช
ํ๋ค.
๊ทธ๋์ ์๊ธฐ๊ฐ ์๋ ํ ์คํธ์ฝ๋๋ก ๋ฉํฐ์ฐ๋ ๋ ํ๊ฒฝ์ ํ ์คํธํด๋ดค๋ค.
ํ ์คํธ๋ ์๋์ฒ๋ผ ์๋น์ค๋ฅผ ๊ฐ๋ตํํด์ ์งํํ๋ค.
- ์์ฝ์ ๋ด์ createdBookings map์ ๋ง๋ ๋ค.
- ์ฐ๋ ๋๋ฅผ 100๊ฐ๋ก ์ง์ ํ ๋ค, ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์ผ๋ก ์์ฒญ์ ๋ ๋ฆฐ๋ค.
- bookingDTO(์์ฝ ์ ๋ณด๋ฅผ ๋ด์ ๊ฐ์ฒด)์ checkin_date์ checkout_date๊ฐ ๊ฐ์ผ๋ฉด ์์ฝ์ด ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ
3-1. ์์ฝ์ด ์ด๋ฏธ ์กด์ฌํ๋ค๋ฉด => createdBookings ๋งต์ ๊ฐ์ ์ถ๊ฐํ์ง ์๋๋ค.
3-2. ์์ฝ์ด ์๋ค๋ฉด => createdBookings ๋งต์ ๊ฐ์ ์ถ๊ฐํ๋ค.
@Test
public void testNoConcurrentBookings() throws InterruptedException {
long startTime = System.currentTimeMillis();
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
Map<String, BookingDto> createdBookings = new HashMap<>();
BookingDto bookingDto = createBookingDto();
for (int i = 0; i < numThreads; i++) {
final String bookingId = UUID.randomUUID().toString();
executorService.submit(() -> {
try {
// ๋์ผํ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์์ ๋ ์ง๋ฅผ ๊ฐ๋ ๊ธฐ์กด ์์ฝ์ด ์๋์ง ํ์ธ
boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
// ์ค๋ณต๋ ์์ฝ์ด ์์ ๊ฒฝ์ฐ์๋ง bookingDto๋ฅผ createdBookings ๋งต์ ์ถ๊ฐ
if (!isDuplicateBooking) {
System.out.println("์ค๋ณต๋ ์์ฝ ์์, createdBookings์ ์ถ๊ฐ");
createdBookings.put(bookingId, bookingDto);
} else {
System.out.println("์ค๋ณต๋ ์์ฝ ๋ฐ๊ฒฌ, createdBookings์ ์ถ๊ฐํ์ง ์์");
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
latch.countDown();
}
});
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
latch.await();
executorService.shutdown();
// ์์ฑ๋ ์์ฝ์ ์๋ฅผ ํ์ธ
System.out.println("createdBookings = " + createdBookings.size());
assertEquals(1, createdBookings.size());
}
//map์ ๊ฐ์ ๋ ์ง๋ฅผ ๊ฐ์ง ์์ฝ๊ฑด์ด ์๋์ง ํ์ธํ๋ ๋ฉ์๋
private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
BookingDto newBooking) {
for (BookingDto existingBooking : createdBookings.values()) {
if (existingBooking.getBooking_checkin_date()
.equals(newBooking.getBooking_checkin_date()) &&
existingBooking.getBooking_checkout_date()
.equals(newBooking.getBooking_checkout_date())) {
return true;
}
}
return false;
}
// bookingDto๋ฅผ ์์ฑํ๋ ๋ฉ์๋
private BookingDto createBookingDto() {
BookingDto bookingDto = new BookingDto();
bookingDto.setBooking_id(UUID.randomUUID().toString());
bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
bookingDto.setStatus_id("B01");
bookingDto.setBooking_checkin_date("2024-02-28");
bookingDto.setBooking_checkout_date("2024-02-29");
bookingDto.setBooking_num_of_guest(1);
bookingDto.setBooking_total_pay_amount(1);
return bookingDto;
}
์๋ฌด๋ฐ ์กฐ์น๋ฅผ ํด์ฃผ์ง ์์์๋ , 100๊ฐ์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๋์์ฑ ๋ฌธ์ ๊ฐ ์ข ์ข ๋ฐ์ํ๋ค.
@Test
public void testSynchronizedBookings() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
HashMap<String, BookingDto> createdBookings = new HashMap<>();
BookingDto bookingDto = createBookingDto();
for (int i = 0; i < numThreads; i++) {
final String bookingId = UUID.randomUUID().toString();
executorService.submit(() -> {
try {
//***** ์๊ณ๊ตฌ์ญ ์ง์ ์์*******//
synchronized (lock) {
// ๋์ผํ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์์ ๋ ์ง๋ฅผ ๊ฐ๋ ๊ธฐ์กด ์์ฝ์ด ์๋์ง ํ์ธ
boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
// ์ค๋ณต๋ ์์ฝ์ด ์์ ๊ฒฝ์ฐ์๋ง bookingDto๋ฅผ createdBookings ๋งต์ ์ถ๊ฐ
if (!isDuplicateBooking) {
System.out.println("์ค๋ณต๋ ์์ฝ ์์, createdBookings์ ์ถ๊ฐ");
createdBookings.put(bookingId, bookingDto);
} else {
System.out.println("์ค๋ณต๋ ์์ฝ ๋ฐ๊ฒฌ, createdBookings์ ์ถ๊ฐํ์ง ์์");
}
}
//***** ์๊ณ๊ตฌ์ญ ์ง์ ๋*******//
} catch (Exception ex) {
ex.printStackTrace();
} finally {
latch.countDown();
}
});
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
latch.await();
executorService.shutdown();
// ์์ฑ๋ ์์ฝ์ ์๋ฅผ ํ์ธ
assertEquals(1, createdBookings.size());
}
//map์ ๊ฐ์ ๋ ์ง๋ฅผ ๊ฐ์ง ์์ฝ๊ฑด์ด ์๋์ง ํ์ธํ๋ ๋ฉ์๋
private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
BookingDto newBooking) {
for (BookingDto existingBooking : createdBookings.values()) {
if (existingBooking.getBooking_checkin_date()
.equals(newBooking.getBooking_checkin_date()) &&
existingBooking.getBooking_checkout_date()
.equals(newBooking.getBooking_checkout_date())) {
return true;
}
}
return false;
}
// bookingDto๋ฅผ ์์ฑํ๋ ๋ฉ์๋
private BookingDto createBookingDto() {
BookingDto bookingDto = new BookingDto();
bookingDto.setBooking_id(UUID.randomUUID().toString());
bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
bookingDto.setStatus_id("B01");
bookingDto.setBooking_checkin_date("2024-02-28");
bookingDto.setBooking_checkout_date("2024-02-29");
bookingDto.setBooking_num_of_guest(1);
bookingDto.setBooking_total_pay_amount(1);
return bookingDto;
}
synchronized ์ ์ด์๋ฅผ ํตํด์ ์๊ณ๊ตฌ์ญ์ ์ง์ ํ ๋ค, ๋ฝ์ ์ฃผ์ด ์ฐ๋ ๋๊ฐ ํ๊ฐ์ฉ๋ง ์ ๊ทผํ ์ ์๋๋ก ํ๋ค.
ํ
์คํธ ๊ฒฐ๊ณผ ๋จ ํ๋์ ์์ฝ๋ง ์์ฑ๋๋ฉด์ ๋ฌด์กฐ๊ฑด ๋์์ฑ์ ๋ณด์ฅํ ์ ์์๋ค!
๊ทธ๋ฌ๋ ํ์คํ ์ฑ๋ฅ์์ผ๋ก๋ ๋๋ ค์ง ๊ฒ์ ํ์ธํ ์ ์์๋ค.
์ฆ, synchronized ์ ์ด์๋ก ๋ฝ์ ์ค์ผ๋ก์จ ๋์์ฑ์ ๋ณด์ฅํ ์ ์์ง๋ง ๊ทธ๋ก ์ธํ ์ฑ๋ฅ ์ ํ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
@Test
public void testConcurrentBookingsWithConcurrentHashMap() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(numThreads);
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
Map<String, BookingDto> createdBookings = new ConcurrentHashMap<>();
BookingDto bookingDto = createBookingDto();
for (int i = 0; i < numThreads; i++) {
final String bookingId = UUID.randomUUID().toString();
executorService.submit(() -> {
try {
// ๋์ผํ ์ฒดํฌ์ธ ๋ฐ ์ฒดํฌ์์ ๋ ์ง๋ฅผ ๊ฐ๋ ๊ธฐ์กด ์์ฝ์ด ์๋์ง ํ์ธ
boolean isDuplicateBooking = checkForDuplicate(createdBookings, bookingDto);
// ์ค๋ณต๋ ์์ฝ์ด ์์ ๊ฒฝ์ฐ์๋ง bookingDto๋ฅผ createdBookings ๋งต์ ์ถ๊ฐ
if (!isDuplicateBooking) {
System.out.println("์ค๋ณต๋ ์์ฝ ์์, createdBookings์ ์ถ๊ฐ");
createdBookings.putIfAbsent(bookingId, bookingDto);
} else {
System.out.println("์ค๋ณต๋ ์์ฝ ๋ฐ๊ฒฌ, createdBookings์ ์ถ๊ฐํ์ง ์์");
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
latch.countDown();
}
});
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
latch.await();
executorService.shutdown();
// ์์ฑ๋ ์์ฝ์ ์๋ฅผ ํ์ธ
System.out.println("createdBookings = " + createdBookings.size());
assertEquals(1, createdBookings.size());
}
//map์ ๊ฐ์ ๋ ์ง๋ฅผ ๊ฐ์ง ์์ฝ๊ฑด์ด ์๋์ง ํ์ธํ๋ ๋ฉ์๋
private boolean checkForDuplicate(Map<String, BookingDto> createdBookings,
BookingDto newBooking) {
for (BookingDto existingBooking : createdBookings.values()) {
if (existingBooking.getBooking_checkin_date()
.equals(newBooking.getBooking_checkin_date()) &&
existingBooking.getBooking_checkout_date()
.equals(newBooking.getBooking_checkout_date())) {
return true;
}
}
return false;
}
// bookingDto๋ฅผ ์์ฑํ๋ ๋ฉ์๋
private BookingDto createBookingDto() {
BookingDto bookingDto = new BookingDto();
bookingDto.setBooking_id(UUID.randomUUID().toString());
bookingDto.setUser_id("f6b58fa7-a088-453a-8533-d6e1d68eec93");
bookingDto.setRoom_id("004f28e1-4c1c-40b3-b580-a2293671110f");
bookingDto.setStatus_id("B01");
bookingDto.setBooking_checkin_date("2024-02-28");
bookingDto.setBooking_checkout_date("2024-02-29");
bookingDto.setBooking_num_of_guest(1);
bookingDto.setBooking_total_pay_amount(1);
return bookingDto;
}
ํ
์คํธ๋ฅผ ํตํด ์์ธ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์๋ค.
๊ตฌ๊ธ๋ง์ ํด๋ดค์ ๋, concurrentHashMap์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๋์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ์๋ฃ๊ตฌ์กฐ๋ก ๋ง์ด ์ ํํ๋ค๋ ๋ ํผ๋ฐ์ค๋ฅผ ๋ง์ด ๋ดค๊ธฐ์ ๋น์ฐํ ์ฑ๊ณต์ผ์ค ์์๋ค!
๊ทธ๋ฐ๋ฐ ์คํจํ๋ ๊ฒฝ์ฐ๊ฐ ์์ ์์๋ค. ๋ํต ์ด์ ๊ฐ ๋ฌด์์ธ์ง ๋ชจ๋ฅด๊ฒ ์ด์ ๋ช์๊ฐ์ ๊ณ ๋ฏผํ๋ค๊ฐ ์๋ ๋ด์ฉ์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐพ์๋ค.
ConcurrentHashMap์ ์กฐํ์ Lock์ ํ ๊น?
concurrentHashMap์ ์กฐํ์์๋ synchronized๊ฐ ๊ตฌํ๋์ด์์ง ์๋ค๋๊ฒ.
ํ์ง๋ง ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ concurrentHashMap์ CAS ์๊ณ ๋ฆฌ์ฆ ๋ฐฉ์์ผ๋ก ๋์์ฑ์ ๋ณด์ฅํด์ผํ๋๋ฐ,
ํ์ฌ ๋ด ํ
์คํธ์ฝ๋์์ ์ค๋ฅ๋ก ์ธํด์ ๋์์ฑ์ ๋ณด์ฅํ์ง ๋ชปํ๊ณ ์๋ ๊ฒ ๊ฐ๋ค.
ํ๋ฃจ์ข ์ผ ์ดํด๋ดค์ง๋ง ์ด๋ค ๋ถ๋ถ์ด ๋ฌธ์ ์ธ์ง ์ ๋ชจ๋ฅด๊ฒ ์ด์, ์ถํ concurrentHashMap๊ณผ ๋์์ฑ์ ๋ํด์ ๋ ๊ณต๋ถํด๋ณด๋ ค๊ณ ํ๋ค!
synchronized๋ฅผ ์ฌ์ฉํ๋ฉด ์๊ณ๊ตฌ์ญ์์ lock์ ์ป์ด ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์์ ๋์์ฑ์ ๋ณด์ฅํ ์ ์๋ค.
..๊ทธ๋ฌ๋!
1.์๋ฒ๊ฐ ์ฌ๋ฌ๋์ผ ๊ฒฝ์ฐ์๋ ์ด ์ ์ด์ ๋ํ ๋์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ด๋ ต๋ค. synchronized๋ ํ๋์ ํ๋ก์ธ์ค์์๋ง ๋์์ฑ์ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ด๋ค.
2.์ฑ๋ฅ์ ๋ํ ์ด์๊ฐ ์๋ค. ์ค์ ๋ก ๋ด๊ฐ ํ ์คํธ ํ์ ๋๋ ์ฝ 1.2~1.5๋ฐฐ์ ์๊ฐ์ด ๋ ๊ฑธ๋ฆฌ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๊ทธ๋ ๋ค๋ฉด?
์ด๋ป๊ฒ ํด์ผํ ์ง ์งํผํฐ์๊ฒ ๋ฌผ์ด๋ดค๋ค.
๐ฉโ๐ป ์ง๋ฌธ : synchronized๋ ๋จ์ผ ํ๋ก์ธ์ค์์๋ง ๋์ํ๊ธฐ๋๋ฌธ์ ์๋ฒ๊ฐ ์ฌ๋ฌ๋์ธ ๊ฒฝ์ฐ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ด๋ ต๋ค๊ณ ํ์์. ๊ทธ๋ผ ์๋ฒ๊ฐ ์ฌ๋ฌ๋์ธ ๊ฒฝ์ฐ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํด? ํค์๋ ์์ฃผ๋ก ์๋ ค์ค ์ ์์ด?
๐ฉโ๐ป ๋ต๋ณ :
๋ง์ต๋๋ค. ์ฌ๋ฌ ๋์ ์๋ฒ์์ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋ช ๊ฐ์ง ๊ธฐ์ ๊ณผ ์์น์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์๋๋ ํค์๋ ์์ฃผ๋ก ์ค๋ช
ํฉ๋๋ค:
๋ถ์ฐ ๋ฝ (Distributed Locking)
:
ZooKeeper, etcd ๋ฑ์ ๋ถ์ฐ ์์คํ
: ๋ถ์ฐ๋ ์๋ฒ ๊ฐ์ ๋์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๊ณต์ ๋ ๋ฆฌ์์ค์ ๋ํ ๋ฝ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํธ๋์ญ์
์ฒ๋ฆฌ:
๋ถ์ฐ ํธ๋์ญ์
(Distributed Transactions)
: ์ฌ๋ฌ ์๋ฒ ๊ฐ์ ํธ๋์ญ์
์ ๊ด๋ฆฌํ์ฌ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ ๋ณต์กํ๊ณ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
๋ฒ์ ๊ด๋ฆฌ (Versioning):
Optimistic Concurrency Control (OCC)
: ๊ฐ ๋ฆฌ์์ค์ ๋ํด ๋ฒ์ ์ ๊ด๋ฆฌํ์ฌ ์ถฉ๋์ ๊ฐ์งํ๊ณ ํด๊ฒฐํ๋ ๋ฐฉ์์ผ๋ก ๋์์ฑ์ ์ ์ดํ ์ ์์ต๋๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ (Asynchronous Processing):
๋ฉ์์ง ํ ๋ฐ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ
: ๋น๋๊ธฐ์ ์ผ๋ก ์์
์ ์ฒ๋ฆฌํ๊ณ ์๋ฒ ๊ฐ์ ํต์ ์ ์ต์ํํ์ฌ ๋์์ฑ ๋ฌธ์ ๋ฅผ ์ํํ ์ ์์ต๋๋ค.
๋ถํ ๊ณผ ์ ๋ณต (Sharding):
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ฉ
: ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ์๋ฒ์ ๋ถ์ฐํ์ฌ ๋ถํ๋ฅผ ๋ถ์ฐํ๊ณ ๋์์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์บ์ ํ์ฉ:
๋ถ์ฐ ์บ์ฑ ์์คํ
: ๊ณตํต ๋ฐ์ดํฐ์ ๋ํ ์บ์ฑ์ ์ฌ์ฉํ์ฌ ๋น๋ฒํ ์ฝ๊ธฐ ์์
์ ๋ถํ๋ฅผ ์ค์ด๊ณ ์๋ต ์๊ฐ์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
๋๊ธฐํ ์๋ ์ํคํ
์ฒ (Asynchronous Architectures):
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ
์ฒ
: ๋
๋ฆฝ์ ์ผ๋ก ๋์ํ๋ ์๋น์ค๋ค์ ์กฐํฉํ์ฌ ๋์์ฑ ๋ฌธ์ ๋ฅผ ์ํํ ์ ์์ต๋๋ค.
CAP ์ด๋ก :
Consistency, Availability, Partition Tolerance
: ์ด ์ธ ๊ฐ์ง ์ค ๋ ๊ฐ์ง๋ง ์ ํ ๊ฐ๋ฅํ๋ฏ๋ก ์์คํ
์ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ์ ์ ํ ์ ํ์ ํด์ผ ํฉ๋๋ค.
Quorum ๊ธฐ๋ฐ ์์คํ
:
๋ถ์ฐ ์์คํ
์์ ๋ค์๊ฒฐ์ ์ด์ฉํ ์์ฌ ๊ฒฐ์
: ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ์์
์ ๋ํ ๋ค์ ๊ฒฐ์ ์ ํตํด ์ผ๊ด์ฑ์ ์ ์งํ๋ฉด์๋ ๊ฐ์ฉ์ฑ์ ํ๋ณดํ ์ ์์ต๋๋ค.
์ด๋ฌํ ๊ธฐ์ ๊ณผ ์์น์ ์กฐํฉํ์ฌ ๋ถ์ฐ ํ๊ฒฝ์์ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์์นญํด๋ดค์๋๋ ๋ถ์ฐ๋ฝ, ๋ ๋์ค, ํธ๋์ญ์ ์ฒ๋ฆฌ ๋ฑ์ ํค์๋๊ฐ ๋ง์ด ๋์์, ์ถํ์ ์๋ฒ๊ฐ ์ฌ๋ฌ๋์ธ ๊ฒฝ์ฐ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ๊ณต๋ถํด๋ณด๋ ค๊ณ ํ๋ค.