๐Ÿ’ป Programming/Java (40)

์š”์ฆ˜ ์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ” Third ์—๋””์…˜ ์ฑ…์„ ๋™๋„ค ๋„์„œ๊ด€์—์„œ ๋Œ€์—ฌํ•ด์„œ ์ฝ๊ณ ์žˆ์Šต๋‹ˆ๋‹ค.

์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”์— ๋Œ€ํ•œ ๊ธ€์„ ์ฝ๋‹ค๊ฐ€ ์†Œ์ˆ˜๊ตฌํ•˜๋Š” ๋กœ์ง์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ž‘์„ฑํ•œ ๋ถ€๋ถ„์„ ๋ณด๊ฒŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์†Œ์ˆ˜๊ตฌํ•˜๊ธฐ ๋กœ์ง์€ ์ด์ง์ค€๋น„ ํ•  ๋•Œ๋‚˜ ๋‹ค์‹œ ๋“ค์—ฌ๋‹ค๋ณผ๋งŒํ•œ๊ฑฐ๋ผ ์˜ค๋ž˜์ „์— for-loop ๋กœ ๊ตฌํ˜„ํ•ด๋ณธ ๊ธฐ์–ต๋งŒ ์žˆ๋‹ค๋ณด๋‹ˆ ์‹ ์„ ํ•˜๊ฒŒ ๋Š๊ปด์กŒ๋„ค์š”.

์•„์ง๋„ ๋งŽ์€ ๋ธ”๋กœ๊ทธ๋“ค์—์„œ for-loop๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•๋“ค๋งŒ ๋งŽ์ด ์†Œ๊ฐœํ•˜๊ณ  ์žˆ๊ธฐ๋„ ํ•˜๊ณ ํ•ด์„œ ํฌ์ŠคํŒ… ์ฃผ์ œ๋กœ ์‚ผ์•„๋ดค์Šต๋‹ˆ๋‹ค. 

๊ฐœ์ธ์ ์ธ ๊ธฐ๋ก๋„ ํ• ๊ฒธ...

์ฑ…์„ ์ฝ๊ณ  ์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ๋ถ€๋ถ„์€ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ๋ถ€๋ถ„๋„ ์žˆ์ง€๋งŒ ์ด๋ฏธ BigInteger ํด๋ž˜์Šค์— isProbablePrime ์ด๋ž€ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์—ˆ๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค..

 

์•„๋ž˜๋Š” ํŠน์ • ์ˆซ์ž n ๊นŒ์ง€ ์†Œ์ˆ˜๊ฐ€ ๋ช‡ ๊ฐœ์ธ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ๊ทธ ๋ชฉ๋ก๋„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

public static void main(String[] args) {
    int n = (int) Math.pow(10, 8);
    // n ๊นŒ์ง€์˜ ์ˆ˜ ์ค‘์— ์†Œ์ˆ˜์˜ ๊ฐœ์ˆ˜ ์ถœ๋ ฅํ•˜๊ธฐ
    long cnt = LongStream.rangeClosed(2, n)
    	    .parallel()
            .mapToObj(BigInteger::valueOf)
            .filter(i -> i.isProbablePrime(50))
            .count();
    System.out.println(cnt);

    // n ๊นŒ์ง€์˜ ์ˆ˜ ์ค‘์— ์†Œ์ˆ˜ ๋ชฉ๋ก ์ถœ๋ ฅํ•˜๊ธฐ
    System.out.println(LongStream.rangeClosed(2, n)
            .mapToObj(BigInteger::valueOf)
            .filter(i -> i.isProbablePrime(50))
            .collect(Collectors.toList()));
}

LongStream์„ ์ด์šฉํ•˜์—ฌ ์ˆซ์ž์˜ ๋ฒ”์œ„๋ฅผ ์ •ํ•˜๊ณ  mapToObj ๋ฅผ ์ด์šฉํ•˜์—ฌ BigInteger๋กœ ๋ณ€ํ˜•ํ•œ๋’ค BigInteger.isProbablePrime(int certainty) ๋ฉ”์„œ๋“œ๋ฅผ ํ•„ํ„ฐ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์†Œ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

BigInteger.isProbablePrime(int certainty) ๋ฉ”์„œ๋“œ๋Š” ์†Œ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ธฐ์œ„ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐ€๋Ÿฌ-๋ผ๋นˆ(Miller-Rabin) ํ…Œ์ŠคํŠธ์™€ ๋ฃจ์นด์Šค-๋ ˆ๋จธ(Lucas-Lehmer) ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ ์š”. ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉ๋œ ๋ฐ€๋Ÿฌ๋ผ๋นˆ ํ…Œ์ŠคํŠธ๋Š” DSA(Digital Signiture Algorithm) ์ŠคํŽ™ (NIST FIPS 186-2)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ–ˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ŠคํŽ™์€ ํŒŒ์ผ๋กœ ์ฒจ๋ถ€ํ•˜๋‹ˆ ๊ด€์‹ฌ์žˆ์œผ์‹  ๋ถ„๋“ค์€ ๋‹ค์šด๋ฐ›์•„ ๋ณด์…”๋„ ๋  ๊ฒƒ ๊ฐ™๋„ค์š”. 

 

fips186-2.pdf
0.35MB

 

์ฐธ๊ณ ๋กœ .parallel() ์€ ์ŠคํŠธ๋ฆผ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ ๋งค์šฐ ์ฃผ์˜๋ฅผ ์š”ํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ฑ…์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ์–˜๊ธฐํ•ฉ๋‹ˆ๋‹ค. Stream.iterate ๋ฅผ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์ด์šฉํ•˜๊ฑฐ๋‚˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์œผ๋กœ limit ์„ ์‚ฌ์šฉํ•˜๋Š” ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ๋Š” parallel์„ ์ด์šฉํ•œ ์„ฑ๋Šฅ๊ฐœ์„ ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์˜คํžˆ๋ ค ์•ˆ์ข‹์•„์งˆ ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ๋ง์ด์ฃ . ์‹ค์ œ๋กœ ์šด์˜ํ™˜๊ฒฝ์—์„œ ์ €๊ฒƒ ๋•Œ๋ฌธ์— ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•œ ์ ๋„ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ๋ฌดํ•œ๋ฃจํ”„์— ๋น ์ง„๊ฒƒ์ฒ˜๋Ÿผ ์“ฐ๋ ˆ๋“œ ํ•˜๋‚˜๊ฐ€ ๋จนํ†ต์ด ๋˜์–ด๋ฒ„๋ฆฌ๋”๊ตฐ์š”. ์ŠคํŠธ๋ฆผ์—์„œ ๋ณ‘๋ ฌ์—ฐ์‚ฐ์— ์ ํ•ฉํ•œ ์ ์€ reduce, min, max, count, sum ๋“ฑ์˜ ์—ฐ์‚ฐ์ด๋ฉฐ, collect์ฒ˜๋Ÿผ ๊ฐ€๋ณ€์ถ•์†Œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ๋ณ‘๋ ฌ์—ฐ์‚ฐ์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์—ˆ๋Š”๋ฐ์š”

์ด์–ด์„œ ์ด๋ฒˆ์—๋Š” ์ถœ๋ ฅ๋˜๋Š” ๋กœ๊ทธ๋ฉ”์‹œ์ง€์˜ ๋‚ด์šฉ์„ ๋ฐ”๊ฟ”๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

ํ˜น์‹œ๋ผ๋„ ๊ฒ€์ƒ‰์œผ๋กœ ์ด ํฌ์ŠคํŒ…์„ ๋จผ์ € ๋ณด๊ฒŒ๋˜์‹œ๋Š” ๋ถ„์€ ์•„๋ž˜ ํฌ์ŠคํŒ…์„ ๋จผ์ € ์ฝ์–ด๋ณด์‹œ๊ธธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

[5๋ถ„์ฝ”๋”ฉ] Filter๋ฅผ ์ด์šฉํ•œ ์š”์ฒญ,์‘๋‹ต ๋กœ๊น… (How to log request, response info inlcuding payload using filter) - (1/2)

 

๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ๋‚ด๋ง˜๋Œ€๋กœ ๊พธ๋ฏธ๊ธฐ

์šฐ์„  ์ง€๋‚œ ์‹œ๊ฐ„์— ๋งˆ์ง€๋ง‰์œผ๋กœ ํ™•์ธํ•œ ๋กœ๊ทธ ์ถœ๋ ฅ ๋‚ด์šฉ์„ ๋‹ค์‹œ ํ™•์ธํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

2022-09-16 07:32:49.190  INFO 31518 --- [nio-8080-exec-5] c.k.demo.filter.RequestLoggingFilter     : Before request [POST /test/request-body-log, client=0:0:0:0:0:0:0:1]
2022-09-16 07:32:49.226  INFO 31518 --- [nio-8080-exec-5] c.k.demo.filter.RequestLoggingFilter     : After request [POST /test/request-body-log, client=0:0:0:0:0:0:0:1, payload={
    "id":1000,
    "name":"์ผ€์ด์น˜",
    "age":20
}]

 

๊ทธ๋Ÿผ ์ € ๋ฉ”์‹œ์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์„์ง€ ํ•œ๋ฒˆ ์•Œ์•„๋ณผ๊ฒŒ์š”.

์š”์ฒญ/์‘๋‹ต ๋กœ๊น…์„ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” AbstractRequestLoggingFilter ๋ฅผ ์ƒ์†ํ•˜์—ฌ ํ•„ํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ”๊พธ๋ ค๋ฉด ์ € ํด๋ž˜์Šค์—์„œ ์–ด๋–ค ๋ฉ”์„œ๋“œ๋“ค์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋“ค์—ฌ๋‹ค๋ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

AbstractRequestLoggingFilter๋ฅผ ๊นŒ๋ณด๋ฉด ์•„๋ž˜ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์„œ ์žฌ์ •์˜ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)

 

doFilterInternal ๋ฉ”์„œ๋“œ์—์„œ ํ•˜๋Š” ์ผ์€ ์š”์ฒญ์— ๋Œ€ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์‹คํ–‰๋˜๊ธฐ ์ „ํ›„๋กœ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ์ž ์‹œ ์‚ดํŽด๋ณผ๊ฒŒ์š”

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   boolean isFirstRequest = !isAsyncDispatch(request);
   HttpServletRequest requestToUse = request;

   if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
      requestToUse = new ContentCachingRequestWrapper(request, getMaxPayloadLength());
   }

   boolean shouldLog = shouldLog(requestToUse);
   if (shouldLog && isFirstRequest) {
      beforeRequest(requestToUse, getBeforeMessage(requestToUse));
   }
   try {
      filterChain.doFilter(requestToUse, response);
   }
   finally {
      if (shouldLog && !isAsyncStarted(requestToUse)) {
         afterRequest(requestToUse, getAfterMessage(requestToUse));
      }
   }
}

 

beforeRequest(requestToUse, getBeforeMessage(requestToUse)) ์—์„œ Before request ... ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์žˆ๊ณ 

afterRequest(requestToUse, getAfterMessage(requestToUse)) ์—์„œ After request ... ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š”๋Œ€๋กœ ๋ฉ”์‹œ์ง€์˜ ๋‚ด์šฉ์„ ๋ฐ”๊พธ๋ ค๋ฉด ์ € ๋‘ ๊ตฐ๋ฐ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์šฐ์„  ๋กœ๊ทธ ๋ฉ”์‹œ์ง€์— ๋Œ€ํ•œ ์ˆ˜์ • ์š”๊ตฌ์‚ฌํ•ญ์ด ์•„๋ž˜์™€ ๊ฐ™๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ํ˜ธ์ถœ๋ฐ›์€ API ์ •๋ณด์™€ ํด๋ผ์ด์–ธํŠธIP ์ •๋ณด๋ฅผ ์ค‘๋ณต ์ถœ๋ ฅ ํ•˜์ง€ ์•Š๋Š”๋‹ค
  2. ํ˜ธ์ถœ๋ฐ›์€ API uri ์™€ ํด๋ผ์ด์–ธํŠธIP, payload ์ •๋ณด๋Š”  before request ์—์„œ ๋‚จ๊ธด๋‹ค.  ๐ŸŒŸ
  3. after request ์—๋Š” ์‘๋‹ต์†Œ์š”์‹œ๊ฐ„๊ณผ http status ์ฝ”๋“œ๊ฐ’์„ ๋‚จ๊ธด๋‹ค.
  4. ์ตœ์ข…์ ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ๋ชจ์Šต์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
2022-09-16 08:28:08.053  INFO 41196 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : REQ: POST uri=/test/request-body-log;client=0:0:0:0:0:0:0:1;payload={
    "id":1000,
    "name":"์ผ€์ด์น˜",
    "age":20
}
2022-09-16 08:28:08.076  INFO 41196 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : RES: 22ms, 400

 

์ž, ์ด์ œ ์œ„ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์šฐ๋ฆฌ์˜ ํ•„ํ„ฐํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. 

RequestLoggingFilter ํด๋ž˜์Šค์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    boolean isFirstRequest = !isAsyncDispatch(request);
    HttpServletRequest requestToUse = request;

    if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
        requestToUse = new ContentCachingRequestWrapper(request);
    }

    long start = System.currentTimeMillis();

    if (isFirstRequest) {
        beforeRequest(requestToUse, getBeforeMessage(requestToUse));
    }

    try {
        filterChain.doFilter(requestToUse, response);
    } finally {
        if (!isAsyncStarted(requestToUse)) {
            afterRequest(requestToUse, getAfterMessage(System.currentTimeMillis() - start, response.getStatus()));
        }
    }
}

private String getBeforeMessage(HttpServletRequest request) {
    return createMessage(request, "REQ: ", "");
}

private String getAfterMessage(long elapsed, int status) {
    return "RES: " + elapsed + "ms, " + status;
}

 

AbstractRequestLoggingFilter ์— ๊ตฌํ˜„๋˜์–ด์žˆ๋Š” doFilterInternal ๋ฉ”์„œ๋“œ ๋‚ด์šฉ์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ง€๊ณ ์™€์„œ beforeRequest์™€ afterRequest ๋ฉ”์„œ๋“œ์˜ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋Š” message ๋ฅผ ์กฐ๋ฆฝํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. getBeforeMessage์˜ createMessage๋Š” superํด๋ž˜์Šค, ์ฆ‰, AbstractRequestLoggingFilter ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. createMessage ์—์„œ๋Š” prefix์™€ suffix ๊ทธ๋ฆฌ๊ณ  request ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ์•Œ์•„์„œ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. payload๋„ ์—ญ์‹œ ์—ฌ๊ธฐ ํฌํ•จ๋˜์–ด์žˆ์ฃ .

์ž, ๊ทธ๋Ÿผ ์•ฑ์„ ์žฌ๊ธฐ๋™ํ•˜๊ณ  ๋กœ๊น…์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2022-09-16 08:39:20.270  INFO 43287 --- [nio-8080-exec-1] c.k.demo.filter.RequestLoggingFilter     : REQ: POST /test/request-body-log, client=0:0:0:0:0:0:0:1
2022-09-16 08:39:20.306  INFO 43287 --- [nio-8080-exec-1] c.k.demo.filter.RequestLoggingFilter     : RES: 35ms, 200

 

์š”๊ตฌ์‚ฌํ•ญ ๋Œ€๋ถ€๋ถ„์ด ๋ฐ˜์˜๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋ผ? ๊ทผ๋ฐ payload ๊ฐ€ request ๋กœ๊ทธ์—์„œ ๋น ์ ธ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถ„๋ช… after message ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋  ๋•Œ๋Š” ์ž˜ ์ถœ๋ ฅ์ด ๋์—ˆ๋Š”๋ฐ ๋ง์ด์ฃ . ๋˜‘๊ฐ™์€ createMessage ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ–ˆ๋Š”๋ฐ before request ์—์„œ๋Š” payload๊ฐ€ ์ถœ๋ ฅ์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค ใ…œใ…œ

ํ™•์ธํ•ด๋ณด๋‹ˆ AbstractRequestLoggingFilter.getMessagePayload ์—์„œ ์•„๋ž˜ wrapper ๊ฐ€ null ๋กœ ๋ฐ˜ํ™˜์ด ๋˜๊ณ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ContentCachingRequestWrapper wrapper =
      WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);

 

res๋กœ๊ทธ์—์„œ๋Š” ์ž˜ ๋‚˜์˜ค๋˜๊ฒŒ req๋กœ๊ทธ์—์„œ ์ถœ๋ ฅํ•˜๋ ค๋‹ˆ null์ด ๋ฐ˜ํ™˜์ด ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฑธ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์ถ”๊ฐ€์ ์ธ ์ž‘์—…์ด ํ•„์š”ํ•œ๋ฐ ์šฐ์„  ์•„๋ž˜ ๋‘ ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

package com.keichee.demo.filter;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class RequestBodyCacheFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new RequestBodyCacheWrapper((HttpServletRequest) servletRequest), servletResponse);
    }
}

 

package com.keichee.demo.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

@Slf4j
public class RequestBodyCacheWrapper extends HttpServletRequestWrapper {

    private final ByteArrayInputStream byteArrayInputStream;

    public RequestBodyCacheWrapper(HttpServletRequest request) throws IOException {
        super(request);
        InputStream is = super.getInputStream();
        byteArrayInputStream = new ByteArrayInputStream(is.readAllBytes());
    }

    @Override
    public ServletInputStream getInputStream() {
        byteArrayInputStream.reset();
        return new MyServletInputStream(byteArrayInputStream);
    }

    @Override
    public BufferedReader getReader() {
        byteArrayInputStream.reset();
        return new BufferedReader(new InputStreamReader(byteArrayInputStream, StandardCharsets.UTF_8));
    }


    private static class MyServletInputStream extends ServletInputStream {

        private final InputStream is;

        public MyServletInputStream(InputStream bis) {
            is = bis;
        }

        @Override
        public int read() throws IOException {
            return is.read();
        }

        @Override
        public int read(byte[] b) throws IOException {
            return is.read(b);
        }

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {
        }
    }
}

 

์ด์ œ ๋‹ค์‹œ RequestLoggingFilter ํด๋ž˜์Šค๋กœ ๋Œ์•„์™€์„œ AbstractRequestLoggingFilter.createMessage ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•ด์„œ ๊ฐ€์ง€๊ณ  ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  getMessagePayload ๋ถ€๋ถ„์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ฃผ์„ธ์š”. ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ ๊ทธ๋Œ€๋กœ ๋†”๋‘ก๋‹ˆ๋‹ค.

String payload = null;
try {
    payload = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
    log.error("failed to read payload", e);
}

 

 

์ˆ˜์ •์ด ์™„๋ฃŒ๋œ createMessage ๋ฉ”์„œ๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@Override
protected String createMessage(HttpServletRequest request, String prefix, String suffix) {
    StringBuilder msg = new StringBuilder();
    msg.append(prefix);
    msg.append(request.getMethod()).append(' ');
    msg.append(request.getRequestURI());

    if (isIncludeQueryString()) {
        String queryString = request.getQueryString();
        if (queryString != null) {
            msg.append('?').append(queryString);
        }
    }

    if (isIncludeClientInfo()) {
        String client = request.getRemoteAddr();
        if (StringUtils.hasLength(client)) {
            msg.append(", client=").append(client);
        }
        HttpSession session = request.getSession(false);
        if (session != null) {
            msg.append(", session=").append(session.getId());
        }
        String user = request.getRemoteUser();
        if (user != null) {
            msg.append(", user=").append(user);
        }
    }

    if (isIncludeHeaders()) {
        HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
        if (getHeaderPredicate() != null) {
            Enumeration<String> names = request.getHeaderNames();
            while (names.hasMoreElements()) {
                String header = names.nextElement();
                if (!getHeaderPredicate().test(header)) {
                    headers.set(header, "masked");
                }
            }
        }
        msg.append(", headers=").append(headers);
    }

    if (isIncludePayload()) {
        String payload = null;
        try {
            payload = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("failed to read payload", e);
        }
        if (payload != null) {
            msg.append(", payload=").append(payload);
        }
    }

    msg.append(suffix);
    return msg.toString();
}

 

๋งˆ์ง€๋ง‰์œผ๋กœ doFilterInternal ๋ฉ”์„œ๋“œ ๋กœ์ง ์ค‘ filterChain.doFilter์—์„œ ์‚ฌ์šฉํ•˜๋Š” request ๊ฐ์ฒด๋ฅผ ContentCachingRequestWrapper ๊ฐ€ ์•„๋‹Œ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์€ request๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. (reuqestToUse -> request)

์ตœ์ข…์ ์œผ๋กœ RequestLoggingFilter ํด๋ž˜์Šค์˜ ์†Œ์Šค์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

package com.keichee.demo.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

@Slf4j
public class RequestLoggingFilter extends AbstractRequestLoggingFilter {

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        boolean isFirstRequest = !isAsyncDispatch(request);
        HttpServletRequest requestToUse = request;

        if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
            requestToUse = new ContentCachingRequestWrapper(request);
        }

        long start = System.currentTimeMillis();

        if (isFirstRequest) {
            beforeRequest(requestToUse, getBeforeMessage(requestToUse));
        }

        try {
            filterChain.doFilter(request, response);
        } finally {
            if (!isAsyncStarted(requestToUse)) {
                afterRequest(requestToUse, getAfterMessage(System.currentTimeMillis() - start, response.getStatus()));
            }
        }
    }

    private String getBeforeMessage(HttpServletRequest request) {
        return createMessage(request, "REQ: ", "");
    }

    private String getAfterMessage(long elapsed, int status) {
        return "RES: " + elapsed + "ms, " + status;
    }

    @Override
    protected String createMessage(HttpServletRequest request, String prefix, String suffix) {
        StringBuilder msg = new StringBuilder();
        msg.append(prefix);
        msg.append(request.getMethod()).append(' ');
        msg.append(request.getRequestURI());

        if (isIncludeQueryString()) {
            String queryString = request.getQueryString();
            if (queryString != null) {
                msg.append('?').append(queryString);
            }
        }

        if (isIncludeClientInfo()) {
            String client = request.getRemoteAddr();
            if (StringUtils.hasLength(client)) {
                msg.append(", client=").append(client);
            }
            HttpSession session = request.getSession(false);
            if (session != null) {
                msg.append(", session=").append(session.getId());
            }
            String user = request.getRemoteUser();
            if (user != null) {
                msg.append(", user=").append(user);
            }
        }

        if (isIncludeHeaders()) {
            HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
            if (getHeaderPredicate() != null) {
                Enumeration<String> names = request.getHeaderNames();
                while (names.hasMoreElements()) {
                    String header = names.nextElement();
                    if (!getHeaderPredicate().test(header)) {
                        headers.set(header, "masked");
                    }
                }
            }
            msg.append(", headers=").append(headers);
        }

        if (isIncludePayload()) {
            String payload = null;
            try {
                payload = new String(request.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
            } catch (IOException e) {
                log.error("failed to read payload", e);
            }
            if (payload != null) {
                msg.append(", payload=").append(payload);
            }
        }

        msg.append(suffix);
        return msg.toString();
    }

}

 

์ž, ์ด์ œ ์•ฑ์„ ์žฌ๊ธฐ๋™ํ•˜๊ณ  ๋‹ค์‹œ API๋ฅผ ํ˜ธ์ถœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2022-09-16 10:04:36.918 DEBUG 57590 --- [           main] com.keichee.demo.DemoLoggingApplication  : Running with Spring Boot v2.7.3, Spring v5.3.22
2022-09-16 10:04:36.918  INFO 57590 --- [           main] com.keichee.demo.DemoLoggingApplication  : The following 1 profile is active: "local"
2022-09-16 10:04:37.301 DEBUG 57590 --- [           main] c.k.demo.filter.RequestBodyCacheFilter   : Filter 'requestBodyCacheFilter' configured for use
2022-09-16 10:04:37.301 DEBUG 57590 --- [           main] c.k.demo.filter.RequestLoggingFilter     : Filter 'loggingFilter' configured for use
2022-09-16 10:04:37.416  INFO 57590 --- [           main] com.keichee.demo.DemoLoggingApplication  : Started DemoLoggingApplication in 0.642 seconds (JVM running for 0.873)
2022-09-16 10:04:39.588  INFO 57590 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : REQ: POST /test/request-body-log, client=0:0:0:0:0:0:0:1, payload={
    "id":1000,
    "name":"์ผ€์ด์น˜",
    "age":20
}
2022-09-16 10:04:39.627  INFO 57590 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : RES: 40ms, 200

 

request payload๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต status๋„ 200์ด ๋‚˜์˜จ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์ž, ์ž˜ ๋”ฐ๋ผ ์˜ค์…จ๋‚˜์š”? 

์ด ๋ถ€๋ถ„์€ trickyํ•œ ๋ถ€๋ถ„์ด๋ผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— request body๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ์• ๋ฅผ ๋จน๋Š” ๋ถ„๋“ค์ด ๋งŽ์Šต๋‹ˆ๋‹ค. stackoverflow์—์„œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ๊ธฐ๋„ ํž˜๋“ค๋”๊ตฐ์š”. ์˜๋„ํ•œ๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์œผ๋‚˜ springboot์— ๋‚ด์žฅ๋œ tomcat์— request body๋ฅผ ํ•œ๋ฒˆ๋งŒ ์ฝ์–ด์„œ ์“ธ ์ˆ˜ ์žˆ๋„๋ก ์ œํ•œ(?)๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž˜๋ชป ์„ค์ •ํ•˜๋ฉด ๋กœ๊ทธ์—๋Š” payload๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜์ง€๋งŒ ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง ์‹คํ–‰์‹œ request body๋ฅผ ๋ชป ์ฝ์–ด์™€์„œ 400 bad request๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

 

์ด์ƒ์œผ๋กœ request, response ๋กœ๊ทธ๋ฅผ ๋‚ด๋ง˜๋Œ€๋กœ ๋ฐ”๊ฟ”๋ณด๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~ ๐Ÿ™‡

์ข‹์•„์š” ๊พน ๋ˆŒ๋Ÿฌ์ฃผ๊ณ  ๊ฐ€์„ธ์š”~ 

๊ฐœ๋ฐœ์ž๋กœ์„œ ์šด์˜์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋กœ๊ทธ๋ฉ”์‹œ์ง€๊ฐ€ ๋””๋ฒ„๊น…์„ ์œ„ํ•ด์„œ ๊ผญ ํ•„์š”ํ•˜๋‹ค๋Š”๊ฑด ๋ˆ„๊ตฌ๋‚˜ ์•Œ๊ณ ๊ณ„์‹ค๊ฒ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋กœ๊น…์„ ์ž˜ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋งŽ์€ ๊ณ ๋ฏผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ๋ ˆ๋ฒจ์€ ์–ด๋–ป๊ฒŒ ํ• ์ง€ ๋กœ๊ทธ์˜ ๋‚ด์šฉ์€ ์–ด๋–ค ์ •๋ณด๋“ค๋กœ ์ฑ„์›Œ๋„ฃ์„์ง€ ๋“ฑ๋“ฑ ๋ง์ด์ฃ .

๋กœ๊ทธ๋Š” ๋งŽ์ด ๋‚จ๊ธด๋‹ค๊ณ  ์ข‹์€๊ฒŒ ์•„๋‹ˆ์ฃ .

์–ด๋–ค ๋ถ„๋“ค์€ ์•„๋ฌด๋Ÿฐ ์˜๋ฏธ๋„ ์—†๋Š” ์ •๋ณด๋ฅผ ๋กœ๊น…ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋น„์šฉ์ ์ธ ์ธก๋ฉด์ด ๋ฌธ์ œ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋Œ€๋Ÿ‰์˜ ๋กœ๊ทธ๋ฅผ ๋งˆ์Œ๊ป ๋‚จ๊ฒจ๋„ ๋˜๊ฒ ์ง€๋งŒ ํ˜„์‹ค์€ ๊ทธ๋ ‡์ง€ ์•Š์ฃ .

๋”ฐ๋ผ์„œ ์ค‘์š”๋„์— ๋”ฐ๋ผ์„œ ์ ๋‹น~~ํžˆ ์ตœ์†Œํ•œ์˜ ๋‚ด์šฉ๋งŒ ๋กœ๊น…ํ•˜๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ ์ค‘์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋กœ๊ทธ๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

API ์š”์ฒญ์‹œ ์–ด๋–ค ์ •๋ณด๋ฅผ ์ „๋‹ฌ๋ฐ›์•˜๋Š”์ง€์— ๋Œ€ํ•œ request log๊ณผ

๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํƒœ์šด ๋’ค์— ์–ด๋–ค ์‘๋‹ต์„ ๋‚ด์ฃผ์—ˆ๋Š”์ง€

response log ๋งŒ ์žˆ์–ด๋„ ๋””๋ฒ„๊น…์€ ์ถฉ๋ถ„ํžˆ ๊ฐ€๋Šฅํ•˜์ฃ .

๋ฌผ๋ก  ์š”์ฒญ๊ณผ ์‘๋‹ต ์ค‘๊ฐ„์— ๋กœ์ง์ด ๋ณต์žกํ•˜๋‹ค๋ฉด ์ค‘๊ฐ„์ค‘๊ฐ„ ์ถ”๊ฐ€์ ์ธ ๋กœ๊ทธ๋ฅผ ์‹ฌ์–ด์ฃผ๋Š”๊ฒŒ ๋งŽ์€ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์–ด๋–ป๊ฒŒ ๋กœ๊น…ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๊ณต์œ ๋“œ๋ฆฌ๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

 

1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

 

๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋ฐœํ™˜๊ฒฝ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • IntelliJ IDEA 2021.3.3 (Ultimate Edition)
  • SpringBoot 2.7.3
  • Java 18 (OpenJDK)

์ž, ์šฐ์„  ๊นกํ†ต ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

์ž, ๊นกํ†ต ํ”„๋กœ์ ํŠธ๊ฐ€ ์™„์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 

 

2. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€

์ด์ œ ๊ฐœ๋ฐœํŽธ์˜๋ฅผ ์œ„ํ•ด lombok๊ณผ ๋กœ๊น…์„ ์œ„ํ•œ logback ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , API ๊ฐœ๋ฐœ์„ ์œ„ํ•ด spring-boot-starter-web ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'ch.qos.logback:logback-classic:1.2.11'

 

3. API ์ž‘์„ฑ

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ŠคํŠธ์šฉ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ•˜๋‚˜ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

package com.keichee.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/log")
    public int requestResponseLog(@RequestParam int code) {
        log.info("requestResponseLog method called with code {}", code);
        return code;
    }
}

 

์—ฌ๊ธฐ๊นŒ์ง€ํ•˜๊ณ  ์•ฑ์„ ๊ธฐ๋™ํ•œ ๋’ค API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋กœ๊ทธ๊ฐ€ ์ž˜ ๋‚จ๋Š”์ง€ ํ™•์ธํ•ด๋ณผ๊ฒŒ์š”.

2022-09-15 17:04:50.580  INFO 92637 --- [           main] com.keichee.demo.DemoLoggingApplication  : No active profile set, falling back to 1 default profile: "default"
2022-09-15 17:04:51.034  INFO 92637 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-09-15 17:04:51.038  INFO 92637 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-09-15 17:04:51.038  INFO 92637 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.65]
2022-09-15 17:04:51.105  INFO 92637 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-09-15 17:04:51.107  INFO 92637 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 495 ms
2022-09-15 17:04:51.306  INFO 92637 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-09-15 17:04:51.312  INFO 92637 --- [           main] com.keichee.demo.DemoLoggingApplication  : Started DemoLoggingApplication in 0.879 seconds (JVM running for 1.294)
2022-09-15 17:05:56.173  INFO 92637 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-09-15 17:05:56.173  INFO 92637 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-09-15 17:05:56.174  INFO 92637 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2022-09-15 17:05:56.186  INFO 92637 --- [nio-8080-exec-1] c.k.demo.controller.TestController       : requestResponseLog method called with code 2

 

์ œ์ผ ๋งˆ์ง€๋ง‰์ค„์— ๋ณด๋ฉด TestController์—์„œ ์ถœ๋ ฅํ•œ ๋กœ๊ทธ๊ฐ€ ๋ณด์ด๋„ค์š”.

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๋กœ๊ทธ๋Š” ์ž˜ ์ถœ๋ ฅ๋˜๊ณ  ์žˆ์œผ๋‹ˆ ์ด์ œ ๊ธฐ๋ณธ์ ์ธ ์ค€๋น„๊ฐ€ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค.

 

4. Filter ๊ตฌํ˜„

์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•œ ๋กœ๊ทธ์ถœ๋ ฅ์„ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” Filter๋ฅผ ์ด์šฉํ•  ๊ฒ๋‹ˆ๋‹ค. 

spring-web์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ filter๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

AbstractRequestLoggingFilter
CharacterEncodingFilter
CommonsRequestLoggingFilter
CompositeFilter
CorsFilter
DelegatingFilterProxy
FormContentFilter
ForwardedHeaderFilter
GenericFilterBean
HiddenHttpMethodFilter
HttpPutFormContentFilter
OncePerRequestFilter
RelativeRedirectFilter
RelativeRedirectResponseWrapper
RequestContextFilter
ServletContextRequestLoggingFilter
ServletRequestPathFilter
ShallowEtagHeaderFilter

 

์—ฌ๊ธฐ์„œ request logging๊ณผ ๊ด€๋ จ๋œ filter๋Š” AbstractRequestLoggingFilter, CommonsRequestLoggingFilter, ๊ทธ๋ฆฌ๊ณ  ServletContextRequestLoggingFilter ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” AbstractRequestLoggingFilter๋ฅผ ์ƒ์†ํ•ด์„œ ์šฐ๋ฆฌ๋งŒ์˜ ํ•„ํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฑฐ์—์š”.

com.keichee.demo ํŒจํ‚ค์ง€ ์•„๋ž˜์— filter ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ์ด ์•ˆ์— RequestLoggingFilter ๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”

package com.keichee.demo.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class RequestLoggingFilter extends AbstractRequestLoggingFilter {

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }
}

 

์ด์ œ ์ด ํ•„ํ„ฐ๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

com.keichee.demo ํŒจํ‚ค์ง€ ์•„๋ž˜์— config ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ์ด ์•ˆ์— RequestLoggingConfig ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

package com.keichee.demo.config;

import com.keichee.demo.filter.RequestLoggingFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RequestLoggingConfig {

    public static int MAX_PAYLOAD_LENGTH = 1000;

    @Bean
    public RequestLoggingFilter loggingFilter() {
        RequestLoggingFilter filter = new RequestLoggingFilter();
        filter.setIncludeClientInfo(true);
        filter.setIncludeHeaders(false);
        filter.setIncludePayload(true);
        filter.setIncludeQueryString(true);
        filter.setMaxPayloadLength(MAX_PAYLOAD_LENGTH);
        return filter;
    }
}

 

ํ—ค๋”์ •๋ณด ๋กœ๊น…์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ setIncludeHeaders(true)๋กœ ์„ค์ •ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

payload์˜ max length๋Š” ๋กœ๊น…๋Ÿ‰๊ณผ ๋กœ๊ทธ๋ฅผ ์ €์žฅํ•˜๋Š” ์‹œ์Šคํ…œ์˜ ์šฉ๋Ÿ‰ ๋“ฑ์— ๋”ฐ๋ผ ์ ๋‹นํžˆ ์„ค์ •ํ•ด์ฃผ์‹œ๋ฉด๋ฉ๋‹ˆ๋‹ค. 

 

์ด์ œ ๋งˆ์ง€๋ง‰ ํ•œ์Šคํ…์ด ๋‚จ์•˜์Šต๋‹ˆ๋‹ค.

logback-spring.xml ํŒŒ์ผ์„ resources ๋””๋ ‰ํ† ๋ฆฌ์— ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>

    <springProfile name="local">
        <logger name="com.keichee.demo" level="debug" additivity="false">
            <appender-ref ref="CONSOLE"/>
        </logger>

        <root level="error">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

</configuration>

 

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ํŒŒ์ผ๋“ค์„ ํฌํ•จํ•˜์—ฌ ์ตœ์ข…์ ์œผ๋กœ ํŒจํ‚ค์ง€ ํŠธ๋ฆฌ๋ฅผ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด์ œ active profile ๊ฐ’์— local ์„ ์ฃผ๊ณ  ์•ฑ์„ ์žฌ๊ธฐ๋™ํ•œ๋’ค ํ•„ํ„ฐ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2022-09-16 07:28:54.399 DEBUG 31518 --- [           main] com.keichee.demo.DemoLoggingApplication  : Running with Spring Boot v2.7.3, Spring v5.3.22
2022-09-16 07:28:54.399  INFO 31518 --- [           main] com.keichee.demo.DemoLoggingApplication  : The following 1 profile is active: "local"
2022-09-16 07:28:54.751 DEBUG 31518 --- [           main] c.k.demo.filter.RequestLoggingFilter     : Filter 'loggingFilter' configured for use
2022-09-16 07:28:54.866  INFO 31518 --- [           main] com.keichee.demo.DemoLoggingApplication  : Started DemoLoggingApplication in 0.607 seconds (JVM running for 0.819)

์ถœ๋ ฅ๋˜๋Š” ๋กœ๊ทธ ์ค‘์— Filter 'loggingFilter' configured for use ๊ฐ€ ์ถœ๋ ฅ๋œ๊ฑธ๋กœ ๋ณด์•„ ์ •์ƒ์ ์œผ๋กœ ์ ์šฉ์ด ๋œ ๊ฒƒ์œผ๋กœ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ๊ธฐ์กด์— ๋งŒ๋“ค์–ด ๋‘์—ˆ๋˜ API๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2022-09-16 07:29:18.541  INFO 31518 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : Before request [GET /test/log?code=2, client=0:0:0:0:0:0:0:1]
2022-09-16 07:29:18.550  INFO 31518 --- [nio-8080-exec-2] c.k.demo.controller.TestController       : requestResponseLog method called with code 2
2022-09-16 07:29:18.560  INFO 31518 --- [nio-8080-exec-2] c.k.demo.filter.RequestLoggingFilter     : After request [GET /test/log?code=2, client=0:0:0:0:0:0:0:1]

์š”์ฒญ์— ๋Œ€ํ•œ ์ •๋ณด uri์™€ query parameter ๊ทธ๋ฆฌ๊ณ  client์— X-Forwarded-For ๊ฐ’์ด ์ถœ๋ ฅ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์‹คํ–‰์ด ๋๋‚œ ๋’ค ์†Œ์š”์‹œ๊ฐ„์ด ์–ผ๋งˆ์ธ์ง€ http status ๊ฐ’์ด ๋ญ”์ง€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ง€๊ธˆ๊นŒ์ง€ ์š”์ฒญ์— ๋Œ€ํ•œ uri, query parameter์™€ API๋ฅผ ์š”์ฒญํ•œ ํด๋ผ์ด์–ธํŠธ์˜ IP ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ ,

์‘๋‹ต์„ ์ฃผ๊ธฐ๊นŒ์ง€์˜ ์†Œ์š”์‹œ๊ฐ„๊ณผ ์‘๋‹ต ์ƒํƒœ๊ฐ’์„ ๋กœ๊น…ํ•˜๋„๋ก ์„ค์ •์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ ์˜ค์…จ๋‚˜์š”? ๐Ÿ˜‹

 

์ด์ œ request body ๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ payload๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š”์ง€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

TestController ์— request body๋ฅผ ๋ฐ›๋Š” API๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@PostMapping("/request-body-log")
public long requestBodyLog(@RequestBody Employee employee) {
    return employee.getId();
}

Employee ์ •๋ณด๋ฅผ ๋ฐ›์•„์„œ id๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ๊ฐ„๋‹จํ•œ API์ž…๋‹ˆ๋‹ค. (์–ด์ฐจํ”ผ request body ๋กœ๊น…์„ ์œ„ํ•œ๊ฑฐ๋‹ˆ ์‹ฌํ”Œํ•˜๊ฒŒ 

 

๊ทธ๋ฆฌ๊ณ  domain ํŒจํ‚ค์ง€ ํ•˜์œ„์— Employee ํด๋ž˜์Šค๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Employee {
    long id;
    String name;
    int age;
}

 

์ด์ œ  ์•ฑ์„ ๊ธฐ๋™ํ•ด์„œ postman์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋กœ๊ทธ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

2022-09-16 07:32:49.190  INFO 31518 --- [nio-8080-exec-5] c.k.demo.filter.RequestLoggingFilter     : Before request [POST /test/request-body-log, client=0:0:0:0:0:0:0:1]
2022-09-16 07:32:49.226  INFO 31518 --- [nio-8080-exec-5] c.k.demo.filter.RequestLoggingFilter     : After request [POST /test/request-body-log, client=0:0:0:0:0:0:0:1, payload={
    "id":1000,
    "name":"์ผ€์ด์น˜",
    "age":20
}]

 

๊ทธ๋Ÿฐ๋ฐ ๋กœ๊ทธ๋ฅผ ๋ณด๋‹ˆ uri ์ •๋ณด์™€ client ์ •๋ณด๊ฐ€ ์ค‘๋ณต๋˜์„œ ์ถœ๋ ฅ์ด ๋˜๊ณ  ์žˆ๊ณ , request body๋กœ ๋„˜๊ฒจ์ค€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋ชจ๋‘ ์‹คํ–‰๋˜๊ณ  ๋‚œ ๋’ค์— ์ถœ๋ ฅ๋˜๋Š” After request ... ๋ถ€๋ถ„์— ์ถœ๋ ฅ์ด ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ญ”๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๋‚ด์šฉ์ด ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋„ค์š”. 

 

๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋กœ๊ทธ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ”๊ฟ”๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~ ๐Ÿ™‡

 

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด ์ข‹์•„์š” ๊พน ๋ˆŒ๋Ÿฌ์ฃผ๊ณ  ๊ฐ€์„ธ์š”~

 

[ ๋‹ค์Œ ํฌ์ŠคํŒ… ๋ฐ”๋กœ ์ฝ๊ธฐ ]

 

[5๋ถ„์ฝ”๋”ฉ] Filter๋ฅผ ์ด์šฉํ•œ ์š”์ฒญ,์‘๋‹ต ๋กœ๊น… (How to log request, response info inlcuding payload using filter) - (2/2)

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์—ˆ๋Š”๋ฐ์š” ์ด์–ด์„œ ์ด๋ฒˆ์—๋Š” ์ถœ๋ ฅ๋˜๋Š” ๋กœ๊ทธ๋ฉ”์‹œ์ง€์˜ ๋‚ด์šฉ์„ ๋‚ด๋ง˜๋Œ€๋กœ ๋ฐ”๊ฟ”๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ˜น์‹œ๋ผ๋„ ๊ฒ€์ƒ‰์œผ๋กœ ์ด ํฌ์ŠคํŒ…

keichee.tistory.com

 

์•ˆ๋…•ํ•˜์„ธ์š”~ ์˜ค๋žœ๋งŒ์— ํฌ์ŠคํŒ…์„ ํ•˜๊ฒŒ๋˜๋„ค์š”.

์˜ค๋Š˜์€ ์Šคํ”„๋ง๋ถ€ํŠธ ๊ธฐ๋ฐ˜์˜ ํ”„๋กœ์ ํŠธ์—์„œ ์Šคํ”„๋ง์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ๊ณต์œ ๋“œ๋ฆฌ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์Šคํ”„๋ง์บ์‹œ๋Š” ๋ ˆ๋””์Šค, ์นดํŽ˜์ธ, ehcache ๋“ฑ๊ณผ ์—ฐ๊ณ„ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ์š”,

์ด๋ฒˆ  ํฌ์ŠคํŒ…์—์„œ๋Š” ehcache์™€ ์—ฐ๋™ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

์šฐ์„  ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋ฐœํ™˜๊ฒฝ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • IntelliJ IDEA 2021.3.3 (Ultimate Edition)
  • SpringBoot 2.7.3
  • Java 18 (OpenJDK)

1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

์šฐ์„  ๋นˆ ๊นกํ†ต ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.

์ด๋ฏธ ์‚ฌ์šฉํ•  ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ฑด๋„ˆ๋›ฐ์…”๋„ ์ข‹์Šต๋‹ˆ๋‹ค :)

์ž๋ฐ” 18, ๊ทธ๋ž˜๋“ค ์„ ํƒ
์•„๋ฌด๋Ÿฐ ์˜์กด์„ฑ์„ ์„ ํƒํ•˜์ง€ ์•Š๊ณ  ๊นจ๋—ํ•œ ํ”„๋กœ์ ํŠธ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค
ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ํ”„๋กœ์ ํŠธ ํŠธ๋ฆฌ

์ž, ๋นˆ๊นกํ†ต ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

2. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ 

์ด์ œ ๊ตฌํ˜„ ๋ฐ ํ…Œ์ŠคํŠธ์— ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์ถ”๊ฐ€ํ•ด๋ณผ๊ฒŒ์š”.

์šฐ์„  ํ˜„์žฌ build.gradle ํŒŒ์ผ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋˜์–ด์žˆ์„๊ฑฐ์—์š”

plugins {
    id 'org.springframework.boot' version '2.7.3'
    id 'io.spring.dependency-management' version '1.0.13.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '18'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

์ €๊ธฐ์— ์•„๋ž˜ 5๊ฐœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

implementation 'org.ehcache:ehcache:3.10.1'
implementation 'org.springframework:spring-context-support:5.3.22'

implementation 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'

implementation 'ch.qos.logback:logback-classic:1.2.11'

์™œ ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ํ•„์š”ํ•œ์ง€ ํ•˜๋‚˜์”ฉ ๋ณผ๊ฒŒ์š”.

implementation 'org.ehcache:ehcache:3.10.1' jcache ๊ตฌํ˜„์ฒด์ธ ehcache ์‚ฌ์šฉ์„ ์œ„ํ•จ
implementation 'org.springframework:spring-context-support:5.3.22' ์Šคํ”„๋ง์บ์‹œ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ
implementation 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
lombok ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ
implementation 'ch.qos.logback:logback-classic:1.2.11' ๋กœ๊น…์„ ์œ„ํ•จ

์ด๋ ‡๊ฒŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•œ ๋’ค ์บ์‹œ์„ค์ •์„ ์ข€ ํ•ด์ฃผ๋„๋ก ํ• ๊ฒŒ์š”

3. ์บ์‹œ ์„ค์ •

com.example.demo.config ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“  ๋’ค ์•„๋ž˜์™€ ๊ฐ™์ด CacheConfig ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

package com.example.demo.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.cache.Cache;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import javax.cache.spi.CachingProvider;
import java.util.concurrent.TimeUnit;

@EnableCaching
@Configuration
public class CacheConfig {

    private final CachingProvider cachingProvider = Caching.getCachingProvider();
    private final javax.cache.CacheManager cacheManager = cachingProvider.getCacheManager();

    @Bean
    public CacheManager cacheManager() {
        return new JCacheCacheManager(cacheManager);
    }

    @Bean
    public Cache<Integer, Integer> commonCache() {
        MutableConfiguration<Integer, Integer> configuration =
                new MutableConfiguration<Integer, Integer>()
                        .setTypes(Integer.class, Integer.class)
                        .setStoreByValue(false)
                        .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, 5)));
        return cacheManager.createCache("commonCache", configuration);
    }
}

์œ„ ๋‚ด์šฉ์„ ๊ฐ„๋žตํžˆ ์‚ดํŽด๋ณด๋ฉด cacheManager ๋นˆ์„ ํ•˜๋‚˜ ๋“ฑ๋กํ•ด์ฃผ๊ณ  ๊ทธ ์บ์‹œ๋งค๋‹ˆ์ €์— commonCache๋ผ๋Š” ์ด๋ฆ„์˜ ์บ์‹œ ๋นˆ์„ ํ•˜๋‚˜ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๊ฒ๋‹ˆ๋‹ค. ์ด commonCache๊ฐ€ key, value ํŽ˜์–ด๋ฅผ ์ €์žฅํ•˜๋Š” ํ•˜๋‚˜์˜ ์„œ๋ž์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด๋˜๊ณ ์š”. ์—ฌ๊ธฐ์„œ๋Š” ํ‚ค์™€ ๊ฐ’์˜ ํƒ€์ž…์ด ๋ชจ๋‘ Integer ์ด๊ณ  ๋งŒ๋ฃŒ์ •์ฑ…์€ ์ƒ์„ฑ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ 5์ดˆ๋กœ ์„ค์ •ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

4. API ๊ตฌํ˜„ ๋ฐ ํ…Œ์ŠคํŠธ

์ด์ œ commonCache์— ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ์บ์‹œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

package com.example.demo.service;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class CacheService {

    @Cacheable(cacheNames = "commonCache", cacheManager = "cacheManager", key = "#code")
    public Integer getCachedValue(int code) {
        System.out.println("๊ณ„์‚ฐ์ค‘....");
        // DB ์กฐํšŒ ๋“ฑ์˜ ๋กœ์ง...
        return (int) (Math.random() * 10);
    }
}

com.example.demo.service ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  CacheService ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

getCachedValue ๋ฉ”์„œ๋“œ์— @Cacheable ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๊ณ  commonCache๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  cacheManager๋Š” CacheConfig์— ๋“ฑ๋กํ–ˆ๋˜ cacheManager ์ด๋ฆ„์„ ์ ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  key๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›๋Š” code ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๊ณ  ์„ ์–ธํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ key๋กœ ์–ด๋–ค ๊ฐ์ฒด์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค๋ฉด key = "#obj.employeeId" ์™€ ๊ฐ™์ด ์‚ฌ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. (๊ณต์‹๋ฌธ์„œ ์ฐธ๊ณ )

CacheService.getCachedValue ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด code ๊ฐ’์„ key๋กœํ•˜์—ฌ return๋œ Integer ๊ฐ’์„ commonCache์— ์ €์žฅํ•˜๊ฒŒ๋˜๊ณ  ๋งŒ๋ฃŒ์‹œ๊ฐ„์ธ 5์ดˆ ์ด๋‚ด์— ๋™์ผํ•œ key๊ฐ’(์—ฌ๊ธฐ์„œ๋Š” code ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’)์œผ๋กœ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํƒ€์ง€์•Š๊ณ  ๋ฐ”๋กœ ์บ์‹œ์— ์ €์žฅ๋˜์–ด์žˆ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ™•์ธํ•˜๊ธฐ์œ„ํ•ด ๊ณ„์‚ฐ์ค‘.... ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋กœ ์œ„ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ…Œ์ŠคํŠธ API ๋ฅผ ๋งŒ๋“ค์–ด ์ค„๊ฒŒ์š”.

com.example.demo.controller ํŒจํ‚ค์ง€๋ฅผ ์‹ ๊ทœ์ถ”๊ฐ€ํ•˜๊ณ  TestController๋ฅผ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

package com.example.demo.controller;

import com.example.demo.service.CacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {

    private final CacheService cacheService;

    @GetMapping("/cache")
    public Integer getCachedValue(int code) {
        log.info("Request accepted for code {}", code);
        return cacheService.getCachedValue(code);
    }
}

API ํ˜ธ์ถœ์ด ๋“ค์–ด์˜ฌ๋•Œ๋งˆ๋‹ค Request accepted for code X ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋˜๋„๋ก ํ•˜๊ณ , ์บ์‹œ์„œ๋น„์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ DemoApplication์„ ์‹คํ–‰ํ•˜๊ณ  API๋ฅผ ํ˜ธ์ถœํ•ด๋ณผ๊ฒŒ์š”.

2022-09-14 12:32:59.783  INFO 47720 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.778 seconds (JVM running for 0.997)
2022-09-14 12:33:06.871  INFO 47720 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-09-14 12:33:06.871  INFO 47720 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-09-14 12:33:06.872  INFO 47720 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2022-09-14 12:33:06.882  INFO 47720 --- [nio-8080-exec-1] c.e.demo.controller.TestController       : Request accepted for code 1
๊ณ„์‚ฐ์ค‘....
2022-09-14 12:33:08.270  INFO 47720 --- [nio-8080-exec-2] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:09.186  INFO 47720 --- [nio-8080-exec-3] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:10.017  INFO 47720 --- [nio-8080-exec-4] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:10.880  INFO 47720 --- [nio-8080-exec-5] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:11.764  INFO 47720 --- [nio-8080-exec-6] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:12.631  INFO 47720 --- [nio-8080-exec-7] c.e.demo.controller.TestController       : Request accepted for code 1
๊ณ„์‚ฐ์ค‘....
2022-09-14 12:33:13.538  INFO 47720 --- [nio-8080-exec-8] c.e.demo.controller.TestController       : Request accepted for code 1
2022-09-14 12:33:14.408  INFO 47720 --- [nio-8080-exec-9] c.e.demo.controller.TestController       : Request accepted for code 1

ํ˜ธ์ถœ์€ ๋ชจ๋‘ code๊ฐ’ 1์„ ๋„ฃ์–ด์„œ ํ•˜์˜€๊ณ , ์ตœ์ดˆ ํ˜ธ์ถœ์„ 12:33:06.882 ์— ํ•˜๋ฉด์„œ ์„œ๋น„์Šค ๋‚ด๋ถ€๋กœ์ง์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. (๊ณ„์‚ฐ์ค‘.... ์ถœ๋ ฅ์œผ๋กœ ํ™•์ธ)

์ดํ›„ 12:33:11.764 ๊นŒ์ง€๋Š” ๊ณ„์‚ฐ์ค‘.... ์ด ์ถœ๋ ฅ๋˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๋ณด์•„ ์บ์‹ฑ๋˜์–ด์žˆ๋Š” ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‘๋‹ตํ•œ๊ฑธ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5์ดˆ๊ฐ€ ์ง€๋‚œ 12:33:12.631 ์— ๋“ค์–ด์˜จ ํ˜ธ์ถœ๊ฑด์€ ๊ณ„์‚ฐ์ค‘.... ์ด ์ถœ๋ ฅ๋œ๊ฑธ๋กœ ๋ณด์•„ ์‘๋‹ต๊ฐ’์— ๋ณ€๋™์ด ๋ฐœ์ƒํ–ˆ์„ ๊ฒƒ์œผ๋กœ ์ถ”์ธก๋ฉ๋‹ˆ๋‹ค. (๋žœ๋ค๊ฐ’์œผ๋กœ ์‘๋‹ตํ•˜๋Š” ์„œ๋น„์Šค๋‹ˆ ์‘๋‹ต๊ฐ’์— ๋ณ€๋™์ด ์—†์„ ์ˆ˜๋„ ์žˆ์ฃ )

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์‘๋‹ต๊ฐ’์— ๋ณ€๋™์ด ์žˆ๋Š๋ƒ๊ฐ€ ์•„๋‹ˆ๋ผ ์บ์‹œ๋˜์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€๋กœ์ง์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ์บ์‹œ์—์„œ ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌํ„ดํ•ด์ค€๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

 

์ด์ƒ์œผ๋กœ 5๋ถ„๋งŒ์— ์Šคํ”„๋ง์บ์‹œ์™€ ehcache๋ฅผ ์ด์šฉํ•˜์—ฌ ์บ์‹œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~  ๐Ÿ™‡

์ž๋ฐ”์—์„œ ๋น„๋™๊ธฐ ํ˜ธ์ถœํ•˜๊ธฐ (AsyncRestTemplate, ListenableFuture)

์•ˆ๋…•ํ•˜์„ธ์š”, ์ตœ๊ทผ์— ๊ด€๋ฆฌ์ž์šฉ ์•ฑ์„ ๊ฐœ์„ ํ•˜๋‹ค๊ฐ€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด์„œ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์žˆ์–ด ํฌ์ŠคํŒ…์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ œ๊ฐ€ ๊ด€๋ฆฌ์ค‘์ธ ๊ด€๋ฆฌ์ž์šฉ ์•ฑ์€ Spring Framework 4, Java 8, Bootstrap 3 ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ž˜๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ๋ฉ”์ธ ์—…๋ฌด๊ฐ€ ์•„๋‹ˆ๋‹ค๋ณด๋‹ˆ ์งฌ๋‚ ๋•Œ ์กฐ๊ธˆ์”ฉ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•ด์ฃผ๊ณ  ์žˆ๋Š”๋ฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด๋‚˜ ์Šคํ”„๋ง ๋ฒ„์ „์„ ์˜ฌ๋ฆฌ๊ธฐ์—” ์ž‘์—…๋Ÿ‰์ด ๋งŽ์•„๋ณด์—ฌ์„œ ์•ˆ๊ฑด๋“œ๋ฆฌ๊ณ  ์žˆ๋„ค์š”.

 

์•„๋ฌดํŠผ ์ž๋ฐ”์—์„œ ๋น„๋™๊ธฐ๋กœ ํ˜ธ์ถœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

์ฒซ ๋ฒˆ์งธ๋Š” callee ๋ฉ”์„œ๋“œ ์ชฝ์—์„œ @Async ๋ฅผ ๋ถ™์—ฌ์„œ ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ ์š”

์ด ๋ฐฉ๋ฒ•์€ callee๊ฐ€ ์™ธ๋ถ€ ํŒ€์ด๊ฑฐ๋‚˜ ์™ธ๋ถ€ ํšŒ์‚ฌ์ผ ๊ฒฝ์šฐ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜ ์ผ์ด ๋นจ๋ฆฌ ์ง„ํ–‰ํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตณ์ด ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ์ง€ ์•Š์€์ด์ƒ callee์ชฝ์— ์š”์ฒญ์„ ํ•  ํ•„์š”๋Š” ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ callee๊ฐ€ ๋‚ด๋ถ€์— ์žˆ๋‹ค๋ฉด ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์กฐ์ƒ ์ด ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋‘ ๋ฒˆ์งธ๋Š” caller๊ฐ€ ํ˜ธ์ถœ๋ฐฉ์‹์„ ์ง์ ‘ ๋น„๋™๊ธฐ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

callee๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋˜์ง€ caller๋Š” ์‹ ๊ฒฝ์“ธ ํ•„์š”๊ฐ€ ์—†์ฃ . 

๋‹จ์ง€ ์‘๋‹ต๋งŒ ์ž˜ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์˜ค๋Š˜ ์†Œ๊ฐœํ•ด ๋“œ๋ฆด ๋‚ด์šฉ์€ ๋‘ ๋ฒˆ์งธ ๋ฐฉ์‹์ธ caller ์ž…์žฅ์—์„œ ๋น„๋™๊ธฐ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์‹ ๋‹ค๋ฉด API ํ˜ธ์ถœํ•˜์‹ค ๋•Œ RestTemplate์„ ์‚ฌ์šฉํ•˜์‹ค ๊ฒ๋‹ˆ๋‹ค.

 

๊ทผ๋ฐ ์Šคํ”„๋ง์—์„œ๋Š” ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์œ„ํ•ด์„œ ์ด๋ฏธ AsyncRestTemplate ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

AsyncRestTemplate ์„ ์ด์šฉํ•ด์„œ API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์€ RestTemplate๊ณผ ๋‹ค๋ฅผ๊ฒŒ ์—†์ฃ .

๊ทธ๋ฆฌ๊ณ  ๋‹น์—ฐํžˆ๋„ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค์Œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ์‘๋‹ต์€ ListenableFuture<ResponseEntity<T>> ํƒ€์ž…์œผ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

    // Autowired๋กœ ์ฃผ์ž…๋œ ์ƒํƒœ๋ผ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
    private final AsyncRestTemplate asyncRestTemplate;
	
    public void test() {
        URI uri = UriComponentsBuilder.fromUriString("http://localhost")
                .path("/test")
                .build()
                .toUri();

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");

        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
        HttpMethod httpMethod = HttpMethod.POST;

        ListenableFuture<ResponseEntity<Void>> res = 
        	asyncRestTemplate.exchange(uri, httpMethod, requestEntity, Void.class);
        log.info("ํ˜ธ์ถœ ์„ฑ๊ณต!!");
    }

์œ„ ์ฝ”๋“œ๋Š” http://localhost/test ๋ฅผ POST ๋ฐฉ์‹์œผ๋กœ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ—ค๋”์— application/json;charset=UTF-8 ์ •๋ณด๋„ ๋„ฃ์–ด์ฃผ๊ณ  ์žˆ๊ณ ์š” ์‘๋‹ต๋ฉ”์‹œ์ง€์— ๋Œ€ํ•ด์„œ๋Š” Void๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฉ”์‹œ์ง€๋ฅผ ์‘๋‹ต์œผ๋กœ ์ฃผ๋˜์ง€ ์‹ ๊ฒฝ์•ˆ์“ด๋‹ค๋Š” ๊ฑฐ๊ฒ ์ฃ .

๊ทธ๋ฆฌ๊ณ  ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ListenableFuture<ResponseEntity<Void>> res ์— ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์‘๋‹ต์„ ๋ฐ›๊ธฐ ์ „์— ํ˜ธ์ถœํ•˜์ž๋งˆ์ž ํ˜ธ์ถœ ์„ฑ๊ณต!! ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋ ‡๊ฒŒ ๋ฐ›์€ ์‘๋‹ต์˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์ •์ƒ๊ณผ ์‹คํŒจ๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค˜์•ผ ํ• ํ…๋ฐ ๊ทธ๊ฑด ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

res ์— callback ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ฝœ๋ฐฑ์„ ์ถ”๊ฐ€ํ•œ ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

    // Autowired๋กœ ์ฃผ์ž…๋œ ์ƒํƒœ๋ผ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
    private final AsyncRestTemplate asyncRestTemplate;

    public void test() {
        URI uri = UriComponentsBuilder.fromUriString("http://localhost")
                .path("/test")
                .build()
                .toUri();

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");

        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
        HttpMethod httpMethod = HttpMethod.POST;

        ListenableFuture<ResponseEntity<Void>> res = asyncRestTemplate.exchange(uri, httpMethod, requestEntity, Void.class);
        res.addCallback(new ListenableFutureCallback<ResponseEntity<Void>>() {
            @Override
            public void onFailure(Throwable th) {
                log.error("์‹คํŒจ");
            }

            @Override
            public void onSuccess(ResponseEntity<Void> voidResponseEntity) {
                if (HttpUtil.isNot2xxSuccessful(voidResponseEntity)) {
                    log.error("์‹คํŒจ, ์‘๋‹ต์ฝ”๋“œ:{}", voidResponseEntity.getStatusCodeValue();
                } else {
                    log.info("์„ฑ๊ณต");
                    // TODO: ์ถ”๊ฐ€ ์ž‘์—…
                }
            }
        });

    }

์—ฌ๊ธฐ์„œ๋Š” annonymous ListenableFutureCallback ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ addCallback ๋ฉ”์„œ๋“œ์— ๋„˜๊ฒจ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

onFailure ์™€ onSuccess ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ์š” ์ด๋•Œ ์ฃผ์˜ํ•  ์ ์ด ํ•˜๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค.

onSuccess ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ผ€์ด์Šค๊ฐ€ 2xx ์„ฑ๊ณต์ธ ์ผ€์ด์Šค๋งŒ์ด ์•„๋‹ˆ๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค.

4xx ์ผ€์ด์Šค๋„ onSuccess ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

onFailure๋Š” SocketTimeout๊ณผ ๊ฐ™์€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์‹ค์งˆ์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์„ฑ๊ณต ์€ response entity์—์„œ ์‘๋‹ต์ฝ”๋“œ๋กœ ํ™•์ธํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ฐธ๊ณ ๋กœ ์œ„ ์ฝ”๋“œ์—์„œ HttpUtil.isNot2xxSuccessful(voidResponseEntity) ๋ฉ”์„œ๋“œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

public class HttpUtil {

    public static boolean is2xxSuccessful(ResponseEntity responseEntity) {
        return HttpStatus.Series.valueOf(responseEntity.getStatusCodeValue())
        	.equals(HttpStatus.Series.SUCCESSFUL);
    }

    public static boolean isNot2xxSuccessful(ResponseEntity responseEntity) {
        return !is2xxSuccessful(responseEntity);
    }
}

ListenableFuture<ResponseEntity<T>> ์—์„œ ์ œ๊ณตํ•˜๋Š” addCallback ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ์•„๋ž˜ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

void addCallback(ListenableFutureCallback<? super T> var1);
void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);

 

์œ„ ์˜ˆ์ œ์—์„œ๋Š” ์ฒซ ๋ฒˆ์งธ addCallback ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค๋งŒ, ๋งŒ์•ฝ SuccessCallback์™€ FailureCallback์„ ๋‚˜๋ˆ ์„œ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ฐ๊ฐ ๊ตฌํ˜„ํ•ด์„œ addCallback ๋ฉ”์„œ๋“œ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•ด์ฃผ์…”๋„ ๋ฉ๋‹ˆ๋‹ค.

 

์ถ”๊ฐ€๋กœ AsyncRestTemplate ์„ ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€๋งŒ ํƒ€์ž„์•„์›ƒ ๋“ฑ ์„ค์ •์„ ๋ฐ”๊ฟ”์„œ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋„์›€์ด ๋˜์‹ค๊ฒ๋‹ˆ๋‹ค.

    @Bean
    public AsyncRestTemplate asyncRestTemplate2() {
        SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
        simpleAsyncTaskExecutor.setTaskDecorator(new MdcTaskDecorator());

        SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        simpleClientHttpRequestFactory.setConnectTimeout(30_000);    // ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„
        simpleClientHttpRequestFactory.setReadTimeout(30_000);       // ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„
        simpleClientHttpRequestFactory.setTaskExecutor(simpleAsyncTaskExecutor);

        AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(simpleClientHttpRequestFactory);

        return asyncRestTemplate;
    }

    static class MdcTaskDecorator implements TaskDecorator {

        @Override
        public Runnable decorate(Runnable runnable) {
            // Web thread context
            Map<String, String> contextMap = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    // @Async thread context
                    MDC.setContextMap(contextMap);
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            };
        }
    }

 

์ด์ƒ์œผ๋กœ AsyncRestTemplate์„ ์ด์šฉํ•˜์—ฌ ์ž๋ฐ”์—์„œ ๋น„๋™๊ธฐ ํ˜ธ์ถœํ•˜๊ธฐ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ AsyncRestTemplate์€ Spring 5๋กœ ๋„˜์–ด๊ฐ€๋ฉด์„œ deprecated ๋˜์—ˆ๊ณ , WebClient๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ถŒ์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Deprecated as of Spring 5.0, in favor of org.springframework.web.reactive.function.client.WebClient

WebClient์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์˜ค๋Š˜๋„ ์ฆํ”„ํ–‰ํ”„ํ•˜์„ธ์š”~

 

 

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” SpringBoot์—์„œ ThreadPoolTaskExecutor๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

SpringBoot ํ”„๋กœ์ ํŠธ๋Š” ์ด๋ฏธ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค๋Š” ์ „์ œํ•˜์— Java11, SpringBoot 2.4.2 ๊ธฐ์ค€์œผ๋กœ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ThreadPoolTaskExecutor์˜ ์„ค์ • ๋ฐ ๊ตฌ์ฒด์ ์ธ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์ด์ „์— ํฌ์ŠคํŒ…ํ•œ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

ThreadPoolTaskExecutor์˜ ์‚ฌ์šฉ๋ฒ•

 

ThreadPoolTaskExecutor๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌํ•˜๊ธฐ(๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ)

async(๋น„๋™๊ธฐ) ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ThreadPoolTaskExecutor ThreadPoolTaskExecutor๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ThreadPoolTaskExecutor๋Š” ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ํด๋ž˜์Šค๋กœ org.springframework.s..

keichee.tistory.com

ThreadPoolTaskExecutor Bean ๋“ฑ๋กํ•˜๊ธฐ

์šฐ์„  ThreadPoolTaskExecutor๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

TaskExecutorConfig ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  @Configuration ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์„ค์ •์„ ์œ„ํ•œ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class TaskExecutorConfig {

	@Bean(name = "executor")
	public ThreadPoolTaskExecutor executor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setThreadNamePrefix("my-");
		return executor;
	}
}

๊ทธ๋ฆฌ๊ณ  executor() ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ThreadPoolTaskExecutor๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋„๋ก ํ•˜๊ณ  @Bean์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด์„œ name ์†์„ฑ์„ ์ง€์ •ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ name ์†์„ฑ์˜ ๊ฐ’์€ ๋ฉ”์„œ๋“œ๋ช…๊ณผ ๋‹ฌ๋ผ๊ณ  ๋ฌด๊ด€ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ํ•ด๋‹น executor๋ฅผ ์ด์šฉํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผฐ์„ ๋•Œ ๋‚ด๊ฐ€ ๋งŒ๋“  ThreadPoolTaskExecutor๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์“ฐ๋ ˆ๋“œ๋ช…prefix๋ฅผ "my-"๋กœ ์„ธํŒ…ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. 

์ด์ „ ํฌ์ŠคํŒ…์„ ์ฝ์–ด๋ณด์…จ๊ฑฐ๋‚˜ ๋˜๋Š” ThreadPoolTaskExecutor๋ฅผ ์ง์—… new ํ‚ค์›Œ๋“œ๋กœ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•ด๋ณด์‹  ๋ถ„์€ ๋ˆˆ์น˜์ฑ„์…จ์„ ์ˆ˜๋„ ์žˆ์„ํ…๋ฐ์š”, ์—ฌ๊ธฐ์„œ initialize()๋ฅผ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ณต์‹๋ฌธ์„œ์—๋Š” initialize ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜์™€์žˆ์ง€๋งŒ ๊ตณ์ด ํ•˜์ง€ ์•Š์•„๋„ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋  ๋•Œ initialize๋ฅผ ํ•˜๋”๊ตฐ์š”.

 

@Autowired ๋กœ ThreadPoolTaskExecutor ์‚ฌ์šฉํ•˜๊ธฐ

์•„๋ž˜๋Š” ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ executor๋ฅผ ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ autowiredํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TestService {

  @Autowired
  @Qualifier("executor")
  private ThreadPoolTaskExecutor executor;

  public void executeThreads() {
      log.info("executing threads....");
      Runnable r = () -> {
          try {
              log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
              Thread.sleep(10000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      };

      for (int i = 0; i < 10; i++) {
          executor.execute(r);
      }
  }
}

TestService๋ผ๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค์—์„œ ๋ฉค๋ฒ„๋ณ€์ˆ˜ executor์— ์œ„์—์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ ๊ฐ์ฒด๋ฅผ ์“ฐ๋„๋ก @Qualifier๋กœ executor ์ด๋ฆ„์„ ๋ช…์‹œํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์“ฐ๋ ˆ๋“œ ๋ช…์ด my-1 ๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. corePoolSize๋ฅผ default ๊ฐ’์ธ 1 ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— my-2, my-3์€ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. corePoolSize ๋ฅผ 2 ์ด์ƒ์œผ๋กœ ์„ธํŒ…ํ•ด์ฃผ๋ฉด my-2, my-3 ๋“ฑ์˜ ์“ฐ๋ ˆ๋“œ๋„ ํ™•์ธ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

2021-01-26 18:16:23.147  INFO 16390 --- [           my-1] com.keichee.test.service.TestService     : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:33.150  INFO 16390 --- [           my-1] com.keichee.test.service.TestService     : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:43.152  INFO 16390 --- [           my-1] com.keichee.test.service.TestService     : my-1, Now sleeping 10 seconds...
2021-01-26 18:16:53.157  INFO 16390 --- [           my-1] com.keichee.test.service.TestService     : my-1, Now sleeping 10 seconds...

 

@Async๋กœ ThreadPoolTaskExecutor ์‚ฌ์šฉํ•˜๊ธฐ

@Async ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜์—ฌ ์œ„์—์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ ThreadPoolTaskExecutor๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด @EnableAsync ๋„ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ TaskExecutorConfig ํด๋ž˜์Šค์— @EnableAsync ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@EnableAsync
@Configuration
public class TaskExecutorConfig {

	@Bean(name = "executor")
	public ThreadPoolTaskExecutor executor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setThreadNamePrefix("my-");
		return executor;
	}
}

 

๊ทธ๋ฆฌ๊ณ  ์„œ๋น„์Šค ๋ ˆ์ด์–ด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TestService {

    @Async("executor")
    public void task() {
        try {
            log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

์ด์ œ controller ์ชฝ์—์„œ task() ๋ฉ”์„œ๋“œ๋ฅผ loop ๋Œ๋ฉด์„œ ํ˜ธ์ถœํ•ด๋ณด๋ฉด @Autowired ๋ฅผ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•˜๊ฒŒ ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.

 

์ด์ƒ์œผ๋กœ SpringBoot์—์„œ ThreadPoolTaskExecutor ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๊ฐ„๋žตํ•˜๊ฒŒ ๋‹ค์‹œ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด

 

1. @Configuration ์œผ๋กœ ๋“ฑ๋กํ•œ ํด๋ž˜์Šค์— executor @Bean ์ถ”๊ฐ€ (@Async ๋ฅผ ์ด์šฉํ•  ๊ฒฝ์šฐ @EnableAsync ๋„ ์ถ”๊ฐ€)

2. @Autowired @Qualifier ๋กœ ์ฃผ์ž…ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋˜๋Š” ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์— @Async ๋ฅผ ๋ถ™์—ฌ ์‚ฌ์šฉ

 

์ด๋ ‡๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”.

 

๊ทธ๋Ÿผ ์˜ค๋Š˜๋„ ํ–‰๋ณตํ•œ ์ฝ”๋”ฉํ•˜์„ธ์š”~

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋‹ค๋ณด๋ฉด DB ์กฐํšŒ ์‹œ์— ์ •๋ ฌํ•ด์„œ ์กฐํšŒํ•ด์˜ค๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ์ •๋ ฌํ•ด์•ผ ํ•  ๋•Œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐฐ์—ด, ๋ฆฌ์ŠคํŠธ, ๋งต, ์…‹์— ๋Œ€ํ•˜์—ฌ ๊ฐ๊ฐ ์˜ค๋ฆ„์ฐจ์ˆœ, ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ๋ฐฐ์—ด ์ •๋ ฌํ•˜๊ธฐ

์šฐ์„  ์•„๋ž˜์™€ ๊ฐ™์ด int ๋ฐฐ์—ด์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

int[] arr = new int[] { 5, 1, 89, 255, 7, 88, 200, 123, 66 };

๋ฐฐ์—ด์˜ ์ •๋ ฌ์€ java.util.Arrays ํด๋ž˜์Šค์— ์žˆ๋Š” sort() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ชจ๋“  primitive ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์›์‹œํƒ€์ž…์ด ์•„๋‹Œ Object[] ๋„ ์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

int[] arr = new int[] { 5, 1, 89, 255, 7, 88, 200, 123, 66 };
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));

Arrays.sort(๋ฐฐ์—ด) ํ˜ธ์ถœ์„ ํ•˜๋ฉด ์ธ์ž๋กœ ๋„˜๊ฒจ์ค€ ๋ฐฐ์—ด์„ ์ •๋ ฌํ•ด์ค๋‹ˆ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  ์ถœ๋ ฅ์„ ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž˜ ์ •๋ ฌ์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[1, 5, 7, 66, 88, 89, 123, 200, 255]

๊ทธ๋Ÿผ ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์–ด๋–ค ๊ฒƒ์ผ๊นŒ์š”?

Java8 ๋ฌธ์„œ์—๋Š” ๋“€์–ผ ํ”ผ๋ด‡ ํ€ต์†ŒํŠธ(Dual-Pivot Quick Sort) ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋‚˜์™€์žˆ์Šต๋‹ˆ๋‹ค.

๋“€์–ผ ํ”ผ๋ด‡ ํ€ต์†ŒํŠธ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์…‹์— ๋Œ€ํ•ด์„œ O(n log(n)) ์˜ ํผํฌ๋จผ์Šค๋ฅผ ๋ณด์ด๊ณ  ์ผ๋ฐ˜์ ์œผ๋กœ ๊ธฐ์กด์˜ One-Pivot ํ€ต์†ŒํŠธ ์ •๋ ฌ๋ณด๋‹ค ๋น ๋ฅด๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Java7 ๋ฌธ์„œ, Java14 ๋ฌธ์„œ์—๋„ ๋™์ผํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜์™€์žˆ์Šต๋‹ˆ๋‹ค.

1.1 ๋ถ€๋ถ„์ •๋ ฌ

์œ„ ์˜ˆ์ œ๋Š” ๋ฐฐ์—ด์˜ ์ „์ฒด ์š”์†Œ๋ฅผ ์ •๋ ฌํ•˜๋Š” ๋ฐ˜๋ฉด ๋ฐฐ์—ด์˜ ์ผ๋ถ€๋ถ„๋งŒ ์ •๋ ฌ์„ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ถ€๋ถ„๋งŒ ์ •๋ ฌํ•  ๋•Œ๋Š” Arrays.sort(int[] a, int fromIndex, int toIndex) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

int[] arr = new int[] { 5, 1, 89, 255, 7, 88, 200, 123, 66 };
Arrays.sort(arr, 0, 4);
System.out.println(Arrays.toString(arr));

์ถœ๋ ฅ์„ ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด 0๋ฒˆ ์ธ๋ฑ์Šค๋ถ€ํ„ฐ 3๋ฒˆ ์ธ๋ฑ์Šค๊นŒ์ง€(4๋Š” exclude์ž…๋‹ˆ๋‹ค) ์ •๋ ฌ์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[1, 5, 89, 255, 7, 88, 200, 123, 66]

 

1.2 ๋ณ‘๋ ฌ ์ •๋ ฌ (ParallelSort)

Arrays.sort()๊ฐ€ ์‹ฑ๊ธ€์“ฐ๋ ˆ๋“œ๋กœ ๋Œ์•„๊ฐ„๋‹ค๋ฉด Arrays.parallelSort()๋Š” ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋กœ ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค. parallelSort๋Š” ๋ฐฐ์—ด์„ sub-array๋กœ ๋‚˜๋ˆˆ ๋’ค ๊ฐ๊ฐ์„ ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ๊ฐ ์“ฐ๋ ˆ๋“œ์—์„œ๋Š” Arrays.sort()๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ •๋ ฌ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Arrays.parallelSort ์˜ ๊ฒฐ๊ณผ๋Š” ๋‹น์—ฐํžˆ Arrays.sort์˜ ๊ฒฐ๊ณผ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ์„ ์ด์šฉํ–ˆ๋Š๋ƒ์˜ ์ฐจ์ด๋งŒ ์กด์žฌํ•  ๋ฟ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ Arrays.parallelSort ๋„ ๋ถ€๋ถ„์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Arrays.parallelSort (int [] a, int fromIndex, int toIndex);

2. List ์ •๋ ฌํ•˜๊ธฐ

๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•  ๋•Œ๋Š” java.util.Collections.sort(List<T> list) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

int[] arr = new int[] { 5, 1, 89, 255, 7, 88, 200, 123, 66 };
List<Integer> toSortList = Ints.asList(arr);    // int[]์„ Integer[]๋กœ ๋ณ€ํ™˜ (๊ตฌ๊ธ€ guava ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ด์šฉ) 
Collections.sort(toSortList);

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” Arrays.sort()๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด comparator๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›๋Š” sortโ€‹(List list, Comparator c) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋„ˆ๋ฌด๋‚˜๋„ ๊ธฐ๋ณธ์ ์ธ ์–˜๊ธฐ์ง€๋งŒ ์ •๋ ฌ์„ ํ•˜๋ ค๋ฉด ๋‘ ์š”์†Œ(element)๋ฅผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์ŠคํŠธ ๋‚ด์˜ ๋ชจ๋“  ์š”์†Œ๋“ค์ด Comparable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Collections.sort(List<T> list) ๋Š” merge sort ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด์šฉํ•˜์—ฌ ์ •๋ ฌ์„ ํ•ฉ๋‹ˆ๋‹ค. List.sort(Comparator c)์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ๋Š” ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค๋งŒ, ๋” ์•ˆ์ข‹๊ฒŒ ๋ณ€ํ˜•๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๊ฒ ์ฃ . ๊ทธ๋ฆฌ๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ List.sort()์—์„œ ์‚ฌ์šฉํ•˜๋Š” merge sort๋Š” ์–ด๋Š์ •๋„ ๋ถ€๋ถ„ ์ •๋ ฌ์ด ๋˜์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด์„œ๋Š” n log(n) ๋ณด๋‹ค ํ›จ์”ฌ ์ ์€ ํšŸ์ˆ˜๋งŒ ๋น„๊ตํ•˜๋ฉฐ(๊ฑฐ์˜ ์ •๋ ฌ์ด ๋˜์–ด์žˆ๋Š” ์ƒํƒœ๋ผ๋ฉด ๊ฑฐ์˜ n๋ฒˆ์˜ ๋น„๊ต๋งŒ์œผ๋กœ๋„ ์ •๋ ฌ ๊ฐ€๋Šฅ), ๋žœ๋คํ•˜๊ฒŒ ์„ž์—ฌ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์…‹์— ๋Œ€ํ•ด์„œ๋Š” ์ „ํ†ต์ ์ธ merge sort์˜ ํผํฌ๋จผ์Šค๋ฅผ ๋‚ธ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. Java14 Collections.sort() ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ ์—ญ์ˆœ(๋‚ด๋ฆผ์ฐจ์ˆœ)์œผ๋กœ ์ •๋ ฌ์„ ํ•˜๊ณ  ์‹ถ์œผ๋ฉด Collections.sort(List list, Comparator c) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

// ๋‚ด๋ฆผ ์ฐจ์ˆœ ์ •๋ ฌ
Collections.sort(list, Comparator.reverseOrder());

์ž๋ฐ”์—์„œ๋Š” ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์„ ์œ„ํ•ด Comparator.reverseOrder() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ comparator๋ฅผ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 

3. Set ์ •๋ ฌํ•˜๊ธฐ

Set์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ LinkedHashSet์€ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜์ฃ . ๋”ฐ๋ผ์„œ Set์„ ์ •๋ ฌํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ด LinkedHashSet ์ฒ˜๋Ÿผ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜๋Š” set ๊ตฌํ˜„์ฒด์— ๋Œ€ํ•œ ์–˜๊ธฐ์ž…๋‹ˆ๋‹ค.

Set์„ ์ •๋ ฌํ•  ๋•Œ๋„ Collections.sort()๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” List๋งŒ์„ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Set์„ ์ •๋ ฌํ•˜๋ ค๋ฉด List๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Set<Integer> set = new LinkedHashSet<>(Ints.asList(arr));
System.out.println(set);    // ์ •๋ ฌํ•˜๊ธฐ ์ „ ์ถœ๋ ฅ

List<Integer> list = new ArrayList<>(set);
Collections.sort(list);
set = new LinkedHashSet<>(list);

System.out.println(set);    // ์ •๋ ฌ ํ›„ ์ถœ๋ ฅ

์œ„์—์„œ ๋ณด๋“ฏ์ด list๋กœ ๋ณ€ํ™˜ ํ›„ ๋‹ค์‹œ set์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ •๋ ฌ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. Map ์ •๋ ฌํ•˜๊ธฐ

Map์€ ์•„์‹œ๋‹ค์‹œํ”ผ key์™€ value ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Map์„ ์ •๋ ฌํ•  ๋•Œ๋Š” key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ value๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•, ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, Map๋„ Set๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ HashMap ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์ˆœ์„œ์™€๋Š” ๋ฌด๊ด€ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ ฌ์„ ์œ„ํ•ด์„œ๋Š” LinkedHashMap์„ ์ด์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์šฐ์„  key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Map์„ ์ •๋ ฌํ•  ๋•Œ๋„ List, Set๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Collections.sort(List list) ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ list๋กœ ๋ณ€ํ™˜์„ ํ•ด์ฃผ์–ด์•ผ ํ•˜์ฃ . ๊ทธ๋ฆฌ๊ณ  ์ •๋ ฌ ํ›„์—๋Š” ์ˆœ์„œ์˜ ๋ณด์žฅ์„ ์œ„ํ•ด list๋ฅผ LinkedHashMap์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ List.sort(Comparator c)๋ฅผ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ์—์„œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ชจ๋‘ ํ™•์ธํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์…‹
HashMap<Integer, String> map = new HashMap<>();
map.put(5, "Orange");
map.put(8, "Apple");
map.put(2, "WaterMelon");
map.put(13, "Pear");
map.put(9, "Grape");
map.put(4, "Banana");


// key, value ๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ entrySet()์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜
List<Map.Entry<Integer, String>> entries = new ArrayList<>(map.entrySet());

// 1. List.sort ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
entries.sort(Comparator.comparing(Map.Entry::getKey));

// 2. Collections.sort ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
Collections.sort(entries, Comparator.comparing(Map.Entry::getKey));

// ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ LinkedHashMap์— ์ €์žฅ
Map<Integer, String> sortedByKey = new LinkedHashMap<>();
for (Map.Entry<Integer, String> entry : entries) {
	sortedByKey.put(entry.getKey(), entry.getValue());
}

// ์ •๋ ฌ๋œ ๋‚ด์šฉ ์ถœ๋ ฅ
System.out.println(sortedByKey);

์ •๋ ฌํ•  ๋•Œ List.sort(Comparator c) ์™€ Collections.sort(List list)๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋‘ ์†Œ๊ฐœํ•ด๋“œ๋ ธ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์‚ฌ์šฉํ•œ Comparator.comparing() ๋ฉ”์„œ๋“œ๋Š” comparator๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. Comparator.comparing(Map.Entry::getKey) ๋Š” Map์˜ key ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” comparator๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์ฃ .

์œ„ ์ฝ”๋“œ์—์„œ ์ถœ๋ ฅ๋˜๋Š” ๋‚ด์šฉ์€ ์•„๋ž˜์™ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{2=WaterMelon, 4=Banana, 5=Orange, 8=Apple, 9=Grape, 13=Pear}

key ๊ฐ’ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ์ด๋ฒˆ์—๋Š” ์œ„ ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ์ˆ˜์ •ํ•˜์—ฌ value๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ์„ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// 1. List.sort ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
entries.sort(Comparator.comparing(Map.Entry::getValue));

// 2. Collections.sort ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
Collections.sort(entries, Comparator.comparing(Map.Entry::getValue));

Comparator.comparing() ๋ฉ”์„œ๋“œ์˜ ์ธ์ž๋กœ key๊ฐ€ ์•„๋‹Œ value ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ˆ˜์ •๋œ ์ฝ”๋“œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{8=Apple, 4=Banana, 9=Grape, 5=Orange, 13=Pear, 2=WaterMelon}

value๊ฐ’์œผ๋กœ ๋„ฃ์–ด์ฃผ์—ˆ๋˜ ๊ณผ์ผ๋ช… ์ˆœ์œผ๋กœ ์ •๋ ฌ์ด ๋˜์–ด ์ถœ๋ ฅ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5. ์ปค์Šคํ…€ ๊ฐ์ฒด ์ •๋ ฌํ•˜๊ธฐ

์ด๋ฒˆ์—๋Š” ์ปค์Šคํ…€ ๊ฐ์ฒด๋ฅผ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ปค์Šคํ…€ ๊ฐ์ฒด๋ฅผ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ๋”ฐ๋กœ ์žˆ๋Š”๊ฑด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋ฏธ ์œ„์—์„œ ์„ค๋ช…๋“œ๋ฆฐ ๋‚ด์šฉ์ค‘์— comparator๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋‹จ ์‡ผํ•‘๋ชฐ์— ํŒ๋งค์ค‘์ธ ์ƒํ’ˆ์— ๋Œ€ํ•œ ๊ฐ์ฒด ์ •์˜๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Getter
@Setter
@AllArgsConstructor
class Product {
    String name;        // ์ƒํ’ˆ ๋ช…
    int price;          // ์ƒํ’ˆ ๊ฐ€๊ฒฉ
    float sellerRating; // ํŒ๋งค์ž ํ‰์ 
    
    @Override
    public String toString() {
    	return "{" + this.name + ", " + price + ", " + sellerRating + "}";
    }
}

์ด์ œ ์ด ๊ฐ์ฒด๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค์–ด ๊ฐ€๊ฒฉ, ํŒ๋งค์ž ํ‰์ ์„ ๊ธฐ์ค€์œผ๋กœ ๊ฐ๊ฐ ์˜ค๋ฆ„์ฐจ์ˆœ, ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ์„ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์…‹
List<Product> data = new ArrayList<>(Arrays.asList(
    new Product("Apple", 100, 4.3f),
    new Product("Apple", 200, 3.3f),
    new Product("Apple", 150, 4.8f)));

// 1. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
data.sort(Comparator.comparing(Product::getPrice));
System.out.println("\n1. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ");
System.out.println(data);

// 2. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
data.sort(Comparator.comparing(Product::getPrice, Comparator.reverseOrder()));
System.out.println("\n2. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ");
System.out.println(data);

// 3. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
Collections.sort(data, Comparator.comparing(Product::getSellerRating));
System.out.println("\n3. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ");
System.out.println(data);

// 4. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
Collections.sort(data, Comparator.comparing(Product::getSellerRating, Comparator.reverseOrder()));
System.out.println("\n4. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ");
System.out.println(data);

Product ๋ฆฌ์ŠคํŠธ๋ฅผ ํŠน์ • ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์ฝ”๋“œ๋Š” List.sort๋ฅผ ์‚ฌ์šฉํ•ด๋„, Collections.sort๋ฅผ ์‚ฌ์šฉํ•ด๋„ ํ•œ ์ค„์ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ์„ ํ•˜๊ณ  ์žˆ์„ ๋•Œ๋Š” Comparator.comparing() ๋ฉ”์„œ๋“œ์— Comparator.reverseOrder() ์ธ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, Comparator.comparing(์ •๋ ฌ๊ธฐ์ค€, ์ •๋ ฌ์ˆœ์„œ) ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋˜๋Š”๊ฑฐ์ฃ .

 

์ž, ์ด์ œ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
[{Apple, 100, 4.3}, {Apple, 150, 4.8}, {Apple, 200, 3.3}]

2. List.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€๊ฒฉ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
[{Apple, 200, 3.3}, {Apple, 150, 4.8}, {Apple, 100, 4.3}]

3. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
[{Apple, 200, 3.3}, {Apple, 100, 4.3}, {Apple, 150, 4.8}]

4. Collections.sort ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒ๋งค์ž ํŽธ์  ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
[{Apple, 150, 4.8}, {Apple, 100, 4.3}, {Apple, 200, 3.3}]

Summary

์—ฌ๊ธฐ๊นŒ์ง€ ์ž๋ฐ”์—์„œ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๊ฐ„๋žตํžˆ ์š”์•ฝ์„ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๋ฐฐ์—ด์˜ ์ •๋ ฌ -> Arrays.sort() ์ด์šฉ

List ์ •๋ ฌ -> Collections.sort(), List.sort() ์ด์šฉ

Set, Map ์ •๋ ฌ -> List๋กœ ๋ณ€ํ™˜ ํ›„ Collections.sort(), List.sort() ์ด์šฉ

๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ

๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์€ Comparator.reverseOrder() ์ด์šฉ

 

์˜ˆ์™ธ ์ฒ˜๋ฆฌ/์—๋Ÿฌ ํ•ธ๋“ค๋ง ์ž˜ํ•˜๊ธฐ

์•ˆ๋…•ํ•˜์„ธ์š”, ์˜ค๋Š˜์€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ(์—๋Ÿฌ ํ•ธ๋“ค๋ง)์— ๋Œ€ํ•ด์„œ ์–˜๊ธฐ๋ฅผ ํ•ด๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค.

์ฑ…์— ๋‚˜์˜ค๋Š” ๋˜๋Š” ์ธํ„ฐ๋„ท ์ƒ์—์„œ ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋Š” try-catch ์˜ˆ์™ธ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์•„๋‹ˆ๊ณ  ์ง์ ‘ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๊ฒฝํ—˜ํ•œ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ข‹๊ฒ ๋‹ค ์‹ถ์€ ๋‚ด์šฉ๋“ค์„ ๊ณต์œ ํ•˜๋Š” ์ฐจ์›์—์„œ ์ž‘์„ฑํ•˜๋Š” ๊ธ€์ž…๋‹ˆ๋‹ค. ํ˜น์—ฌ๋‚˜ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‚˜ ๊ณต์œ ํ•ด์ฃผ์‹œ๊ณ  ์‹ถ์€ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

 

์šฐ์„  ์ž๋ฐ” ์„œ์ ์ด๋‚˜ ๊ตฌ๊ธ€๋ง์„ ํ•ด์„œ ์ฐพ๋Š” ์—๋Ÿฌ ํ•ธ๋“ค๋ง์— ๋Œ€ํ•œ ๋‚ด์šฉ๋“ค์€ ๋Œ€๋ถ€๋ถ„ try-catch ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค์—์„œ ๋๋‚ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋‹จ์ˆœํžˆ ๊ทธ๋ ‡๊ฒŒ ์ž‘์—…ํ•˜๋ฉด ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ์ž˜ํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋‹ค๋ณด๋ฉด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋“ค์„ ๋„˜๋‚˜๋“ค๋ฉด์„œ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋“ค์„ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๋ฉ”์„œ๋“œ ์ฝœ ์ฒด์ธ

์œ„ ๋ฉ”์„œ๋“œ ์ฝœ ์ฒด์ธ์€ ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค(๊ธฐ๋Šฅ)์ด ์ฒ˜๋ฆฌ๋  ๋•Œ์˜ ๊ณผ์ •์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค๋ฉด controller -> service -> dao ๋ญ ์ด๋Ÿฐ ๊ฑด๋ฐ์š”, ์•„๋ฌด๋ฆฌ ๋ณต์žกํ•œ ์„œ๋น„์Šค๋ผ ํ•˜๋”๋ผ๋„ ๊ฒฐ๊ตญ ์š”์ฒญ์—์„œ๋ถ€ํ„ฐ ์‘๋‹ต์„ ์ฃผ๊ธฐ๊นŒ์ง€์˜ ๊ณผ์ •์€ ๊ฒฐ๊ตญ ์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ํ•œ ์ค„๋กœ ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜์ฃ .

 

๋”ฐ๋ผ์„œ ์–ด๋Š ์‹œ์ ์— try-catch ๋กœ ์˜ˆ์™ธ๋ฅผ ์žก์•„์•ผ ํ• ์ง€ ๊ทธ๋ฆฌ๊ณ  ์˜ˆ์™ธ๋ฅผ ์žก์•˜๋‹ค๋ฉด ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ• ์ง€์— ๋Œ€ํ•ด ๋งŽ์€ ๊ณ ๋ฏผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ƒ ๊ทธ๋Ÿฐ ๊ณ ๋ฏผ์„ ๋ณ„๋กœ ํ•˜์ง€ ์•Š๊ณ  ๋Œ€์ถฉ ์—๋Ÿฌ๋กœ๊ทธ ์ฐ์–ด๋†“๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ๋งŽ์€ ๊ฒƒ์ด ์‚ฌ์‹ค์ด์ฃ . ์‹ฌ์ง€์–ด catch๋กœ ์žก์•„์„œ ๋กœ๊ทธ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋‹ค์‹œ throw๋ฅผ ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ํญํƒ„๋Œ๋ฆฌ๊ธฐ ํ•˜๋Š” ๊ฒƒ๋„ ์•„๋‹ˆ๊ณ  ๋ง์ด์ฃ  -_-;; ์ตœ์•…์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๊ฐœ๋ฐœ๋œ ์„œ๋น„์Šค๋Š” ํ•˜๋‚˜์˜ ์—๋Ÿฌ์— ๋Œ€ํ•ด์„œ ์ค‘๋ณต์ ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  ๋””๋ฒ„๊น…๋„ ๋น„ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค์–ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ฒƒ์ผ๊นŒ์š”?

 

์ฒซ ๋ฒˆ์งธ๋Š” ์š”์ฒญ์„ ๋ฐ›์•„์„œ ์‘๋‹ต์„ ์ฃผ๊ธฐ๊นŒ์ง€ ํ•˜๋‚˜์˜ ์ฒด์ธ์—์„œ ํŠน์ • ์˜ˆ์™ธ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋Š” ํ•œ ๊ณณ์—์„œ๋งŒ ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์œ„ ์ฒด์ธ ๊ทธ๋ฆผ์—์„œ ๋ฉ”์„œ๋“œ 1, 2, 3, 4 ์ค‘ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ์—์„œ๋งŒ A๋ผ๋Š” ์˜ˆ์™ธ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค๋Š”๊ฑฐ์ฃ . ์ปจํŠธ๋กค๋Ÿฌ ๋ถ€๋ถ„์—์„œ ExceptionHandler๋ฅผ ์ด์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๊ณ  ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ try-catch ๋ฌธ์„ ์ด์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ3์—์„œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋†“์•˜๋Š”๋ฐ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฉ”์„œ๋“œ2์—์„œ ๋˜ ํ•˜๊ณ  ์žˆ๋‹ค๊ฑฐ๋‚˜ ํ•œ๋‹ค๋ฉด ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ œ๊ฑฐํ•˜๋Š”๊ฒŒ ์œ ์ง€๋ณด์ˆ˜ํ•˜๋Š”๋ฐ ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

 

๋‘ ๋ฒˆ์งธ๋Š” catch๋ฅผ ํ–ˆ์œผ๋ฉด ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค˜์•ผ ํ•œ๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ "์ ์ ˆํ•œ" ์ด๋ผ๋Š” ๋ง์ด ์• ๋งคํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ์š”, ๋‹จ์ˆœํžˆ ๋กœ๊ทธ๋งŒ ์ฐ๊ณ  catchํ•œ ์˜ˆ์™ธ๋ฅผ ๋‹ค์‹œ throw ํ•˜๊ณ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น try-catch๋ฌธ์€ ์“ธ๋ชจ์—†๋Š” ๊ฒƒ์ผ ๊ฐ€๋Šฅ์„ฑ์ด 99.9%์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ๋ผ๋ฉด callee์—์„œ๋งŒ catchํ•ด์„œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š”๊ฒŒ ๋” ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค. ๊ตณ์ด ๋‘ ๊ตฐ๋ฐ์„œ ๋‚˜๋ˆ„์–ด catchํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฑฐ์ฃ . ๋˜, ์–ด๋–ค ์˜ˆ์™ธ๋Š” ์žก์•„์„œ ๋กœ๊ทธ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋ฌด์‹œํ•  ์ˆ˜๋„ ์žˆ๊ณ  (์˜ต์…”๋„ ๊ฐ’์ด ์—†๋‹ค๊ฑฐ๋‚˜ ํ•˜๋Š” ๊ฒฝ์šฐ), ์–ด๋–ค ์˜ˆ์™ธ๋Š” ๋””๋ฒ„๊น…์šฉ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋กค๋ฐฑํ•˜๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋ฅผ ์ง„ํ–‰ํ•จ์— ์žˆ์–ด์„œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ง€๋Š” API์ŠคํŽ™ ๋˜๋Š” ์ •์ฑ…์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ๊ฒ๋‹ˆ๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋กœ, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๊ฒฝ์šฐ ๋””๋ฒ„๊น…์šฉ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ธฐ๋กœ ํ–ˆ๋‹ค๋ฉด ์ •๋ง ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•œ ์ค„์˜ ๋กœ๊ทธ๋งŒ ์ž˜ ๋‚จ๊ฒจ๋„ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์‰ฝ๋„๋ก ์ž‘์„ฑํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜ ํšจ์œจ์„ฑ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋กœ๊น… ์‹œ์Šคํ…œ์— ๋ถ€ํ•˜๋„ ์ค„์ผ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ œ ๊ฒฝํ—˜์„ ํ† ๋Œ€๋กœ ์‹ ์ž… ๋˜๋Š” ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค๊ป˜์„œ ์ด๋ ‡๊ฒŒ ํ•ด๋ณด์‹œ๋ฉด ์ข‹๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์œผ๋กœ ๋„์ ์—ฌ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

ํ˜น์‹œ ์ด ๊ธ€์„ ์ฝ์œผ์‹œ๋‹ค๊ฐ€ ๋ฉ‹์ง„ ๋…ธํ•˜์šฐ๊ฐ€ ์žˆ์œผ์‹  ๋ถ„๋“ค์€ ๋Œ“๊ธ€๋กœ ๊ณต์œ  ๋ถ€ํƒ๋“œ๋ ค์š” ^-^

 

1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์•„์ง ์•ˆ๋ณด์…จ๋‹ค๋ฉด ๋ณด๊ณ  ์˜ค์„ธ์š”~ >> 1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ(์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”)

1์ฐจ์› ๋ฐฐ์—ด์ด 1์—ด๋กœ ๋œ ์ €์žฅ๊ณต๊ฐ„์ด์—ˆ๋‹ค๋ฉด 2์ฐจ์› ๋ฐฐ์—ด์€ matrix(ํ–‰๋ ฌ)์„ ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

2์ฐจ์› ๋ฐฐ์—ด ์„ ์–ธ

์ž๋ฐ”์—์„œ 2์ฐจ์› ๋ฐฐ์—ด์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        int[][] array;  // O
        int [][]array;  // X
        int array[][];  // X
    }

์ง€๋‚œ 1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ ์‹œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ œ์ผ ์œ„์˜ ๋ฐฉ๋ฒ•์œผ๋กœ๋งŒ ๋ฌธ๋ฒ•์  ์˜ค๋ฅ˜ ์—†์ด ์ •์ƒ์ ์œผ๋กœ 2์ฐจ์› ๋ฐฐ์—ด์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

2์ฐจ์› ๋ฐฐ์—ด์˜ ์ดˆ๊ธฐํ™”

2์ฐจ์› ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array;  // 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ

        array = new int[1][5];	// 2์ฐจ์› ๋ฐฐ์—ด์˜ ์ดˆ๊ธฐํ™”
    }

 

2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•˜๋Š” ๋ฐฉ๋ฒ•

2์ฐจ์› ๋ฐฐ์—ด๋„ 1์ฐจ์› ๋ฐฐ์—ด์ฒ˜๋Ÿผ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        
        int[][] array = new int[1][5];  // 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ ๋ฒˆ์—

    }

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐฐ์—ด ๋‚ด์—๋Š” 0์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

1์ฐจ์› ๋ฐฐ์—ด๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ์ดˆ๊ธฐํ™”๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array = {{1,2,3}, {4,5,6}};

    }

์ด๋ ‡๊ฒŒ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๊ธฐ๋ณธ๊ฐ’์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์—ฌ ์ •ํ•ด์ฃผ๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด๊ฒ ์ฃ .

 

์ž, ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๊ณ  ๊ณต๊ฐ„์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ์ž‘์—…์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๋ฐฐ์—ด์— ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ํ•œ ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

2์ฐจ์› ๋ฐฐ์—ด ์ถœ๋ ฅํ•˜๊ธฐ

1์ฐจ์› ๋ฐฐ์—ด์„ ์ถœ๋ ฅํ•  ๋•Œ๋Š” Arrays.toString() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ 2์ฐจ์› ๋ฐฐ์—ด์„ ์ถœ๋ ฅํ•  ๋•Œ๋Š” ๊ทธ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์™œ๋ƒ๋ฉด 2์ฐจ์› ๋ฐฐ์—ด์€ ๋ฐฐ์—ด ์•ˆ์— ๋ฐฐ์—ด์ด ์žˆ๋Š” ํ˜•ํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฐฐ์—ด์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Object ์ด๊ณ  Object์˜ toString์ด ํ˜ธ์ถœ๋˜์–ด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ณ„๋„๋กœ ์ถœ๋ ฅ๋ฌธ์„ ๊ตฌํ˜„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์‰ฝ๊ฒŒํ•˜๋ ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ loop๋ฅผ ํ•œ๋ฒˆ ๋Œ๋ฆฌ๋ฉด์„œ ์ถœ๋ ฅ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // ๊ตฌ๊ตฌ๋‹จ ๊ฒฐ๊ณผ๊ฐ’ ์ €์žฅ์„ ์œ„ํ•œ 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”

        for (int i = 0; i < array.length; i++) {
            System.out.println(Arrays.toString(array[i]));
        }
    }

 

๊ทธ๋Ÿผ ์—ฐ์Šต์‚ผ์•„ 2์ฐจ์› ๋ฐฐ์—ด์•ˆ์— ๊ตฌ๊ตฌ๋‹จ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด๋ณด๋„๋ก ํ•ด๋ณผ๊ฒŒ์š”.

 

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // ๊ตฌ๊ตฌ๋‹จ ๊ฒฐ๊ณผ๊ฐ’ ์ €์žฅ์„ ์œ„ํ•œ 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”

	// ๋ฐฐ์—ด์— ๊ตฌ๊ตฌ๋‹จ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ์ €์žฅ
        for (int i = 2; i < 10; i++) {
            for (int j = 1; j < 10; j++) {
                array[i-2][j-1] = i * j;
            }
        }

	// ๋ฐฐ์—ด์— ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅ
        for (int i = 0; i < array.length; i++) {
            System.out.print((i + 2) + "๋‹จ: ");
            System.out.print(Arrays.toString(array[i]));
            System.out.println();
        }
    }
    
    
    // ์ถœ๋ ฅ ๊ฒฐ๊ณผ
    2๋‹จ: [2, 4, 6, 8, 10, 12, 14, 16, 18]
    3๋‹จ: [3, 6, 9, 12, 15, 18, 21, 24, 27]
    4๋‹จ: [4, 8, 12, 16, 20, 24, 28, 32, 36]
    5๋‹จ: [5, 10, 15, 20, 25, 30, 35, 40, 45]
    6๋‹จ: [6, 12, 18, 24, 30, 36, 42, 48, 54]
    7๋‹จ: [7, 14, 21, 28, 35, 42, 49, 56, 63]
    8๋‹จ: [8, 16, 24, 32, 40, 48, 56, 64, 72]
    9๋‹จ: [9, 18, 27, 36, 45, 54, 63, 72, 81]

 

๋กœ์ง์„ ํ•œ๋ฒˆ ๋ณด๋ฉด ํฌ๊ฒŒ ๊ตฌ๊ตฌ๋‹จ์„ ์ €์žฅํ•  ๋•Œ์™€ ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ๋ถ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  for-loop๋ฌธ์˜ ์กฐ๊ฑด๊ฑธ์— ํ•˜๋“œ์ฝ”๋”ฉํ•œ ์ˆซ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•˜๊ณ  array.length ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๊ธ‰์  array.length ์˜ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋ฉฐ 2์ฐจ์› ๋ฐฐ์—ด์—์„œ array.length๋Š” ํ–‰์ด ๋ช‡ ๊ฐœ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , array[x].length๋Š” ์—ด์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ๊ตฌ๋‹จ์€ ๋ณดํ†ต 2๋‹จ๋ถ€ํ„ฐ 9๋‹จ๊นŒ์ง€์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ์‚ฌ์ด์ฆˆ๋ฅผ 8ํ–‰, 9์—ด๋กœ ์ •์˜๋ฅผ ํ•˜์˜€๊ณ , array.length ๋Š” 8, array[x].length ๋Š” 9 ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

 

 

์ด์ƒ์œผ๋กœ ์ž๋ฐ”์—์„œ 2์ฐจ์› ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ ๋’ค ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ ๊นŒ์ง€ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์งˆ๋ฌธ์žˆ์œผ์‹œ๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์„ธ์š”~

 

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด ๊ณต๊ฐ~ ๊พธ~~~์šฑ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š” ^-^

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~

์ดํด๋ฆฝ์Šค ์Šคํ”„๋งํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•

์ด๋ฒˆ์—๋Š” ์ดํด๋ฆฝ์Šค์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•œ ์Šคํ”„๋งํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ๊ฒŒ์š”.

์ดํด๋ฆฝ์Šค๊ฐ€ ์„ค์น˜์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰ํ•˜์‹œ๋ฉด๋ฉ๋‹ˆ๋‹ค.

 

1. ์ดํด๋ฆฝ์Šค ์ƒ๋‹จ ๋ฉ”๋‰ด์—์„œ Help > Eclipse Marketplace... ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

 

 

2. ๊ฒ€์ƒ‰์ฐฝ์— spring ์œผ๋กœ ๊ฒ€์ƒ‰ํ•œ ๋’ค ์ œ์ผ ์ƒ๋‹จ์— Spring Tools (aka Spring Tools Suite) ๊ฐ€ ๋ณด์ด๋ฉด install ๋ฒ„ํŠผ ํด๋ฆญ (2020๋…„ 7์›” ํ˜„์žฌ ์ตœ์‹  ๋ฒ„์ „์€ 4.7.0.RELEASE)

๋งŒ์•ฝ 4.7.0 ๋ฒ„์ „์ด ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ดํด๋ฆฝ์Šค ๋ฒ„์ „์ด ์˜ค๋ž˜๋œ ๊ฑด ์•„๋‹Œ์ง€ ํ™•์ธํ•ด๋ณด์‹œ๊ณ  ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์ดํด๋ฆฝ์Šค๋ฅผ ๋‹ค์‹œ ๋‹ค์šด๋ฐ›์•„ ์„ค์น˜ํ•˜์‹  ๋’ค ์ง„ํ–‰ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

3. required ํ•ญ๋ชฉ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ฒดํฌ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

 

4. ๋ผ์ด์„ผ์Šค ๋™์˜๋ฅผ ์„ ํƒํ•˜๊ณ  Finish ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

์ด์ƒ์œผ๋กœ ์ดํด๋ฆฝ์Šค์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์œ ์šฉํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šคํ”„๋ง ํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์„ ๋งˆ์นฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์ŠคํŠธ๋ฆผ์„ ์ด์šฉํ•œ ์œ ์šฉํ•œ ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•

ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์€ java์˜ stream์„ ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๊ฐ€๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌ ํ•ด๋†“์€ ๋ฌธ์„œ๋กœ

์œ ์šฉํ•œ ์ผ€์ด์Šค๋ฅผ ๋ฐœ๊ฒฌํ•  ๋•Œ๋งˆ๋‹ค ๊ณ„์† ์—…๋ฐ์ดํŠธํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

 

1. String๋ฐฐ์—ด์„ int๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

int[] intArray = Stream.of(stringArray).mapToInt(Integer::parseInt).toArray();

2. Integer๋ฐฐ์—ด์„ String๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

String[] stringArray = Stream.of(arr).map(String::valueOf).toArray(String[]::new);

3. String๋ฐฐ์—ด์„ String๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

String[] stringArray = new String[]{"!", "@", "#"};
List<String> stringList = Stream.of(stringArray).collect(Collectors.toList());

4. String๋ฆฌ์ŠคํŠธ๋ฅผ String๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

List<String> stringList = new ArrayList<>(Arrays.asList("!","@","#"));
String[] stringArray = stringList.toArray(new String[0]);

5. stream().map()์„ ์ด์šฉํ•œ ๊ฐ์ฒด(object) ๋ณ€ํ™˜ํ•˜๊ธฐ

// ๋ณ€ํ™˜ ์ „ ํด๋ž˜์Šค
@Getter
class Soldier {
  String name;
  int age;

  public Soldier(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

// ๋ณ€ํ™˜ ๋Œ€์ƒ ํด๋ž˜์Šค
@Getter
class King {
  String name;
  int age;
  public King(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

// ์ƒ˜ํ”Œ Soldier stream ์ƒ์„ฑ
Stream<Soldier> s = Stream.of(new Soldier("A", 18), new Soldier("B", 22), new Soldier("C", 19));

// map()์„ ์ด์šฉํ•˜์—ฌ ๋ณ€ํ™˜ํ•˜๊ธฐ
List<King> k = s.map(soldier -> new King(soldier.getName(), soldier.getAge()))
		.collect(Collectors.toList());

 

6. filter()๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•„ํ„ฐ๋งํ•˜๊ธฐ

// ๋ณ€ํ™˜ ์ „ ํด๋ž˜์Šค
@Getter
class Soldier {
  String name;
  int age;

  public Soldier(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

// ๋ณ€ํ™˜ ๋Œ€์ƒ ํด๋ž˜์Šค
@Getter
class King {
  String name;
  int age;
  public King(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

// ์ƒ˜ํ”Œ Soldier stream ์ƒ์„ฑ
Stream<Soldier> s = Stream.of(new Soldier("Arthur", 18), new Soldier("Belisarius", 22), new Soldier("Caesar", 19));

// filter()๋ฅผ ์ด์šฉํ•˜์—ฌ Arthur๋งŒ ๊ณจ๋ผ์„œ map()์„ ์ด์šฉํ•˜์—ฌ King์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ
List<King> k = s.filter(soldier -> "Arthur".equals(soldier.getName()))
    .map(soldier -> new King(soldier.getName(), soldier.getAge()))
    .collect(Collectors.toList());

 

7. min() / max() ๋ฅผ ์ด์šฉํ•˜์—ฌ comparator ๊ธฐ์ค€ ์ตœ์†Œ / ์ตœ๋Œ€ ๊ฐ’์„ ๊ฐ–๋Š” ๊ฐ์ฒด ์ถ”์ถœํ•˜๊ธฐ

    @Getter
    @Setter
    class Datapoint {
        private Double maximum;
    }
    
    public void sortStream() {
        List<Datapoint> datapoints = new ArrayList<>();
        int max = 10;
        datapoints.add(new Datapoint().withMaximum(Math.random() * max));
        datapoints.add(new Datapoint().withMaximum(Math.random() * max));
        datapoints.add(new Datapoint().withMaximum(Math.random() * max));
        log.debug("data points: {}", datapoints);

        // ๊ฐ์ฒด ๋ชฉ๋ก ์ค‘ ํŠน์ • ํ•„๋“œ(maximum)๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ตœ๋Œ€๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฐ์ฒด ์ถ”์ถœ (stream.max() ์ด์šฉ)
        Datapoint datapointMax = datapoints.stream()
                .max(Comparator.comparing(Datapoint::getMaximum))
                .orElse(new Datapoint().withMaximum(0D));
        log.debug("data point MAX: {}", datapointMax);

        // ๊ฐ์ฒด ๋ชฉ๋ก ์ค‘ ํŠน์ • ํ•„๋“œ(maximum)๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ตœ์†Œ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฐ์ฒด ์ถ”์ถœ (stream.min() ์ด์šฉ)
        Datapoint datapointMin = datapoints.stream()
                .min(Comparator.comparing(Datapoint::getMaximum))
                .orElse(new Datapoint().withMaximum(0D));
        log.debug("data point MIN: {}", datapointMin);
    }
    
    
    
    // ์‹คํ–‰ ๋กœ๊ทธ
    data points: [{Maximum: 5.471390124016474,}, {Maximum: 2.7559360370945916,}, {Maximum: 0.5778257233234019,}]
    data point MAX: {Maximum: 5.471390124016474,}
    data point MIN: {Maximum: 0.5778257233234019,}

 

§ ์“ฐ๋ ˆ๋“œ ๊ธฐ๋ณธ ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ๋Š” [Java] ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

 

ThreadPoolExecutor ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ

java.util.concurrent ํŒจํ‚ค์ง€๋Š” ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ด€๋ จํ•˜์—ฌ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋ชจ์•„๋‘” ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋Š” ThreadPoolExecutor๊ฐ€ ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์„ ์ด์šฉํ•˜๋ฉด ์†์‰ฝ๊ฒŒ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ์„  ์ƒ์„ฑ์ž์— ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)


๊ธฐ๋ณธ์ ์œผ๋กœ corePoolSize, maximumPoolSize, keepAliveTime, timeUnit ๊ทธ๋ฆฌ๊ณ  workQueue๋ฅผ ์ž…๋ ฅ๋ฐ›๊ณ  ์žˆ๋„ค์š”.

๊ฐ ํ•ญ๋ชฉ์ด ์˜๋ฏธํ•˜๋Š” ๋ฐ”๊ฐ€ ๋ญ”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. java doc์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค๋ช…์ด ๋‚˜์™€์žˆ์Šต๋‹ˆ๋‹ค.

* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

* @param maximumPoolSize the maximum number of threads to allow in the pool

* @param keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

* @param unit the time unit for the {@code keepAliveTime} argument

* @param workQueue the queue to use for holding tasks before they are executed.


๊ฐ„๋‹จํžˆ ๋งํ•˜๋ฉด corePoolSize๋Š” ์“ฐ๋ ˆ๋“œ ํ’€์˜ ๊ธฐ๋ณธ ์‚ฌ์ด์ฆˆ๋กœ ๋ช‡ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ pool์— ๊ฐ€์ง€๊ณ  ์žˆ์„์ง€์— ๋Œ€ํ•œ ๊ฐ’์ด๊ณ , maximumPoolSize๋Š” ์“ฐ๋ ˆ๋“œ ํ’€์˜ max size๋กœ ์ด ์‚ฌ์ด์ฆˆ๋ฅผ ๋„˜์–ด๊ฐ€๋ฉด RejectedExecutionException์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. keepAliveTime์€ idle ์“ฐ๋ ˆ๋“œ์˜ keep alive time์ด๋ฉฐ, timeUnit์€ keepAliveTime์˜ ์‹œ๊ฐ„๋‹จ์œ„๋ฅผ, ๊ทธ๋ฆฌ๊ณ  workQueue๋Š” corePoolSize๋ฅผ ๋„˜์–ด์„œ๋Š” ์“ฐ๋ ˆ๋“œ๋“ค์„ queueing ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ์ด์ œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, blockingQueue);

        Runnable task = new Task();
        for (int i = 0; i < 100; i++) {
            threadPoolExecutor.execute(task);
        }
        System.out.println("์“ฐ๋ ˆ๋“œ ์ฝœ ์ข…๋ฃŒ");
    }
    
    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", num=" + num++);
            }
        }
    }

 

์œ„ ์ฝ”๋“œ์—์„œ ThreadPoolExecutor์˜ corePoolSize์™€ maximumPoolSize๋ฅผ ๊ฐ๊ฐ 100, 100 ์œผ๋กœ ์„ค์ •์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 100๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ๊ฐ task๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. (๋”๋ณด๊ธฐ ํด๋ฆญํ•ด์„œ ๋ณด์„ธ์š”)

๋”๋ณด๊ธฐ

pool-1-thread-3, num=1
pool-1-thread-3, num=4
pool-1-thread-4, num=3
pool-1-thread-2, num=0
pool-1-thread-2, num=8
pool-1-thread-2, num=9
pool-1-thread-1, num=2
pool-1-thread-6, num=11
pool-1-thread-6, num=13
pool-1-thread-6, num=14
pool-1-thread-7, num=15
pool-1-thread-7, num=17
pool-1-thread-7, num=18
pool-1-thread-7, num=19
pool-1-thread-7, num=20
pool-1-thread-7, num=21
pool-1-thread-2, num=10
pool-1-thread-2, num=24
pool-1-thread-2, num=25
pool-1-thread-2, num=26
pool-1-thread-2, num=27
pool-1-thread-2, num=28
pool-1-thread-2, num=29
pool-1-thread-4, num=7
pool-1-thread-4, num=31
pool-1-thread-4, num=32
pool-1-thread-4, num=33
pool-1-thread-4, num=34
pool-1-thread-4, num=35
pool-1-thread-4, num=36
pool-1-thread-4, num=37
pool-1-thread-4, num=38
pool-1-thread-3, num=6
pool-1-thread-3, num=39
pool-1-thread-3, num=40
pool-1-thread-3, num=41
pool-1-thread-3, num=42
pool-1-thread-3, num=43
pool-1-thread-3, num=44
pool-1-thread-3, num=45
pool-1-thread-10, num=46
pool-1-thread-10, num=47
pool-1-thread-5, num=5
pool-1-thread-5, num=49
pool-1-thread-11, num=50
pool-1-thread-11, num=52
pool-1-thread-11, num=53
pool-1-thread-11, num=54
pool-1-thread-11, num=56
pool-1-thread-11, num=57
pool-1-thread-11, num=58
pool-1-thread-11, num=59
pool-1-thread-11, num=60
pool-1-thread-11, num=61
pool-1-thread-13, num=62
pool-1-thread-13, num=63
pool-1-thread-13, num=64
pool-1-thread-14, num=65
pool-1-thread-14, num=67
pool-1-thread-10, num=48
pool-1-thread-15, num=69
pool-1-thread-15, num=71
pool-1-thread-15, num=72
pool-1-thread-15, num=73
pool-1-thread-15, num=74
pool-1-thread-15, num=75
pool-1-thread-15, num=76
pool-1-thread-9, num=30
pool-1-thread-9, num=79
pool-1-thread-9, num=80
pool-1-thread-9, num=81
pool-1-thread-9, num=82
pool-1-thread-9, num=83
pool-1-thread-9, num=84
pool-1-thread-9, num=85
pool-1-thread-9, num=86
pool-1-thread-9, num=87
pool-1-thread-7, num=23
pool-1-thread-7, num=89
pool-1-thread-7, num=90
pool-1-thread-7, num=91
pool-1-thread-8, num=22
pool-1-thread-8, num=92
pool-1-thread-8, num=93
pool-1-thread-8, num=94
pool-1-thread-8, num=96
pool-1-thread-8, num=97
pool-1-thread-8, num=98
pool-1-thread-8, num=99
pool-1-thread-8, num=100
pool-1-thread-6, num=16
pool-1-thread-1, num=12
pool-1-thread-1, num=104
pool-1-thread-1, num=105
pool-1-thread-1, num=106
pool-1-thread-1, num=108
pool-1-thread-1, num=109
pool-1-thread-1, num=110
pool-1-thread-1, num=111
pool-1-thread-6, num=103
pool-1-thread-6, num=113
pool-1-thread-6, num=114
pool-1-thread-6, num=115
pool-1-thread-6, num=116
pool-1-thread-6, num=117
pool-1-thread-8, num=102
pool-1-thread-19, num=101
pool-1-thread-19, num=120
pool-1-thread-18, num=95
pool-1-thread-18, num=123
pool-1-thread-18, num=124
pool-1-thread-18, num=125
pool-1-thread-18, num=126
pool-1-thread-18, num=127
pool-1-thread-18, num=128
pool-1-thread-18, num=129
pool-1-thread-18, num=130
pool-1-thread-18, num=131
pool-1-thread-17, num=88
pool-1-thread-25, num=133
pool-1-thread-25, num=135
pool-1-thread-25, num=136
pool-1-thread-25, num=137
pool-1-thread-26, num=138
pool-1-thread-26, num=140
pool-1-thread-26, num=141
pool-1-thread-15, num=78
pool-1-thread-15, num=143
pool-1-thread-15, num=144
pool-1-thread-27, num=145
pool-1-thread-27, num=146
pool-1-thread-16, num=77
pool-1-thread-10, num=70
pool-1-thread-10, num=150
pool-1-thread-10, num=151
pool-1-thread-10, num=152
pool-1-thread-10, num=154
pool-1-thread-10, num=155
pool-1-thread-10, num=156
pool-1-thread-14, num=68
pool-1-thread-14, num=157
pool-1-thread-14, num=159
pool-1-thread-14, num=160
pool-1-thread-14, num=161
pool-1-thread-14, num=162
pool-1-thread-13, num=66
pool-1-thread-13, num=164
pool-1-thread-13, num=165
pool-1-thread-32, num=166
pool-1-thread-12, num=55
pool-1-thread-33, num=169
pool-1-thread-5, num=51
pool-1-thread-5, num=172
pool-1-thread-5, num=174
pool-1-thread-5, num=175
pool-1-thread-5, num=176
pool-1-thread-5, num=177
pool-1-thread-5, num=179
pool-1-thread-5, num=180
pool-1-thread-33, num=171
pool-1-thread-33, num=181
pool-1-thread-33, num=182
pool-1-thread-33, num=183
pool-1-thread-12, num=170
pool-1-thread-12, num=185
pool-1-thread-12, num=186
pool-1-thread-12, num=188
pool-1-thread-12, num=189
pool-1-thread-12, num=190
pool-1-thread-12, num=191
pool-1-thread-12, num=192
pool-1-thread-12, num=194
pool-1-thread-38, num=195
pool-1-thread-32, num=168
pool-1-thread-32, num=197
pool-1-thread-32, num=198
pool-1-thread-32, num=199
pool-1-thread-32, num=201
pool-1-thread-32, num=202
pool-1-thread-32, num=203
pool-1-thread-13, num=167
pool-1-thread-40, num=205
pool-1-thread-40, num=207
pool-1-thread-40, num=208
pool-1-thread-40, num=209
pool-1-thread-40, num=210
pool-1-thread-40, num=212
pool-1-thread-40, num=213
pool-1-thread-40, num=214
pool-1-thread-14, num=163
pool-1-thread-14, num=217
pool-1-thread-43, num=218
pool-1-thread-43, num=219
pool-1-thread-43, num=220
pool-1-thread-43, num=221
pool-1-thread-43, num=222
pool-1-thread-31, num=162
pool-1-thread-30, num=158
pool-1-thread-30, num=226
pool-1-thread-30, num=227
pool-1-thread-30, num=228
pool-1-thread-30, num=229
pool-1-thread-45, num=230
pool-1-thread-45, num=232
pool-1-thread-45, num=233
pool-1-thread-45, num=234
pool-1-thread-45, num=235
pool-1-thread-45, num=236
pool-1-thread-45, num=237
pool-1-thread-45, num=239
pool-1-thread-45, num=240
pool-1-thread-29, num=153
pool-1-thread-29, num=242
pool-1-thread-29, num=243
pool-1-thread-29, num=244
pool-1-thread-29, num=245
pool-1-thread-29, num=247
pool-1-thread-29, num=248
pool-1-thread-29, num=249
pool-1-thread-29, num=250
pool-1-thread-29, num=251
pool-1-thread-16, num=149
pool-1-thread-16, num=252
pool-1-thread-16, num=253
pool-1-thread-16, num=254
pool-1-thread-16, num=255
pool-1-thread-16, num=256
pool-1-thread-16, num=257
pool-1-thread-16, num=258
pool-1-thread-16, num=259
pool-1-thread-48, num=260
pool-1-thread-27, num=148
pool-1-thread-27, num=262
pool-1-thread-27, num=263
pool-1-thread-27, num=264
pool-1-thread-27, num=265
pool-1-thread-27, num=266
pool-1-thread-27, num=267
pool-1-thread-27, num=268
pool-1-thread-28, num=147
pool-1-thread-28, num=269
pool-1-thread-28, num=270
pool-1-thread-28, num=271
pool-1-thread-28, num=272
pool-1-thread-28, num=273
pool-1-thread-28, num=274
pool-1-thread-28, num=275
pool-1-thread-28, num=276
pool-1-thread-28, num=278
pool-1-thread-26, num=142
pool-1-thread-26, num=279
pool-1-thread-26, num=280
pool-1-thread-26, num=281
pool-1-thread-26, num=282
pool-1-thread-25, num=139
pool-1-thread-25, num=284
pool-1-thread-25, num=286
pool-1-thread-25, num=287
pool-1-thread-25, num=288
pool-1-thread-25, num=290
pool-1-thread-17, num=134
pool-1-thread-52, num=291
pool-1-thread-52, num=293
pool-1-thread-24, num=132
pool-1-thread-53, num=295
pool-1-thread-53, num=297
pool-1-thread-53, num=298
pool-1-thread-53, num=299
pool-1-thread-53, num=300
pool-1-thread-53, num=302
pool-1-thread-53, num=303
pool-1-thread-53, num=304
pool-1-thread-53, num=305
pool-1-thread-53, num=306
pool-1-thread-55, num=307
pool-1-thread-55, num=308
pool-1-thread-55, num=309
pool-1-thread-55, num=310
pool-1-thread-55, num=311
pool-1-thread-55, num=312
pool-1-thread-55, num=313
pool-1-thread-55, num=314
pool-1-thread-55, num=315
pool-1-thread-55, num=316
pool-1-thread-23, num=122
pool-1-thread-56, num=317
pool-1-thread-56, num=318
pool-1-thread-56, num=319
pool-1-thread-56, num=320
pool-1-thread-56, num=321
pool-1-thread-23, num=322
pool-1-thread-23, num=324
pool-1-thread-23, num=325
pool-1-thread-23, num=326
pool-1-thread-19, num=121
pool-1-thread-19, num=328
pool-1-thread-19, num=329
pool-1-thread-19, num=330
pool-1-thread-19, num=332
pool-1-thread-19, num=333
pool-1-thread-19, num=334
pool-1-thread-19, num=335
pool-1-thread-22, num=119
pool-1-thread-22, num=336
pool-1-thread-22, num=337
pool-1-thread-21, num=118
pool-1-thread-21, num=340
pool-1-thread-21, num=341
pool-1-thread-21, num=342
pool-1-thread-21, num=343
pool-1-thread-1, num=112
pool-1-thread-59, num=345
pool-1-thread-20, num=107
pool-1-thread-59, num=346
pool-1-thread-59, num=348
pool-1-thread-59, num=349
pool-1-thread-59, num=350
pool-1-thread-21, num=344
pool-1-thread-21, num=353
pool-1-thread-21, num=354
pool-1-thread-21, num=355
pool-1-thread-21, num=356
pool-1-thread-22, num=339
pool-1-thread-22, num=358
pool-1-thread-58, num=338
pool-1-thread-58, num=360
pool-1-thread-58, num=361
pool-1-thread-58, num=362
pool-1-thread-58, num=363
pool-1-thread-58, num=364
pool-1-thread-62, num=365
pool-1-thread-57, num=331
pool-1-thread-57, num=368
pool-1-thread-57, num=369
pool-1-thread-57, num=371
pool-1-thread-57, num=372
pool-1-thread-57, num=373
pool-1-thread-57, num=375
pool-1-thread-57, num=376
pool-1-thread-57, num=377
pool-1-thread-57, num=378
pool-1-thread-23, num=327
pool-1-thread-65, num=379
pool-1-thread-65, num=380
pool-1-thread-65, num=382
pool-1-thread-65, num=383
pool-1-thread-65, num=384
pool-1-thread-56, num=323
pool-1-thread-56, num=387
pool-1-thread-56, num=388
pool-1-thread-56, num=389
pool-1-thread-56, num=390
pool-1-thread-54, num=301
pool-1-thread-54, num=391
pool-1-thread-54, num=392
pool-1-thread-54, num=394
pool-1-thread-54, num=395
pool-1-thread-54, num=396
pool-1-thread-54, num=397
pool-1-thread-54, num=398
pool-1-thread-54, num=399
pool-1-thread-54, num=401
pool-1-thread-24, num=296
pool-1-thread-24, num=403
pool-1-thread-52, num=294
pool-1-thread-52, num=406
pool-1-thread-52, num=407
pool-1-thread-52, num=408
pool-1-thread-52, num=410
pool-1-thread-52, num=411
pool-1-thread-52, num=412
pool-1-thread-52, num=413
pool-1-thread-17, num=292
pool-1-thread-17, num=415
pool-1-thread-17, num=416
pool-1-thread-17, num=418
pool-1-thread-74, num=419
pool-1-thread-50, num=289
pool-1-thread-50, num=422
pool-1-thread-75, num=423
pool-1-thread-75, num=425
pool-1-thread-75, num=426
pool-1-thread-51, num=285
pool-1-thread-51, num=428
pool-1-thread-51, num=431
pool-1-thread-51, num=432
pool-1-thread-77, num=430
pool-1-thread-77, num=434
pool-1-thread-77, num=435
pool-1-thread-77, num=436
pool-1-thread-77, num=437
pool-1-thread-77, num=439
pool-1-thread-77, num=440
pool-1-thread-26, num=283
pool-1-thread-79, num=442
pool-1-thread-79, num=444
pool-1-thread-49, num=277
pool-1-thread-49, num=446
pool-1-thread-49, num=447
pool-1-thread-49, num=448
pool-1-thread-49, num=449
pool-1-thread-49, num=450
pool-1-thread-49, num=451
pool-1-thread-49, num=452
pool-1-thread-48, num=261
pool-1-thread-47, num=246
pool-1-thread-47, num=456
pool-1-thread-47, num=457
pool-1-thread-47, num=459
pool-1-thread-82, num=460
pool-1-thread-45, num=241
pool-1-thread-83, num=463
pool-1-thread-83, num=464
pool-1-thread-46, num=238
pool-1-thread-83, num=465
pool-1-thread-83, num=466
pool-1-thread-83, num=467
pool-1-thread-83, num=469
pool-1-thread-83, num=471
pool-1-thread-83, num=472
pool-1-thread-83, num=473
pool-1-thread-83, num=474
pool-1-thread-30, num=231
pool-1-thread-30, num=475
pool-1-thread-30, num=476
pool-1-thread-30, num=477
pool-1-thread-30, num=478
pool-1-thread-31, num=225
pool-1-thread-43, num=224
pool-1-thread-43, num=481
pool-1-thread-43, num=482
pool-1-thread-43, num=483
pool-1-thread-43, num=484
pool-1-thread-86, num=485
pool-1-thread-86, num=486
pool-1-thread-86, num=487
pool-1-thread-86, num=488
pool-1-thread-86, num=489
pool-1-thread-86, num=490
pool-1-thread-86, num=491
pool-1-thread-86, num=492
pool-1-thread-86, num=493
pool-1-thread-86, num=494
pool-1-thread-44, num=223
pool-1-thread-44, num=495
pool-1-thread-44, num=496
pool-1-thread-44, num=497
pool-1-thread-44, num=498
pool-1-thread-44, num=499
pool-1-thread-44, num=500
pool-1-thread-44, num=501
pool-1-thread-44, num=502
pool-1-thread-44, num=503
pool-1-thread-42, num=216
pool-1-thread-42, num=504
pool-1-thread-42, num=505
pool-1-thread-42, num=506
pool-1-thread-42, num=507
pool-1-thread-42, num=508
pool-1-thread-42, num=509
pool-1-thread-42, num=510
pool-1-thread-42, num=511
pool-1-thread-42, num=512
pool-1-thread-40, num=215
pool-1-thread-40, num=514
pool-1-thread-41, num=211
pool-1-thread-41, num=515
pool-1-thread-41, num=516
pool-1-thread-41, num=517
pool-1-thread-41, num=519
pool-1-thread-41, num=520
pool-1-thread-41, num=521
pool-1-thread-41, num=522
pool-1-thread-41, num=523
pool-1-thread-41, num=524
pool-1-thread-13, num=206
pool-1-thread-13, num=525
pool-1-thread-13, num=526
pool-1-thread-32, num=204
pool-1-thread-32, num=527
pool-1-thread-89, num=528
pool-1-thread-89, num=529
pool-1-thread-89, num=530
pool-1-thread-89, num=531
pool-1-thread-89, num=532
pool-1-thread-89, num=533
pool-1-thread-89, num=534
pool-1-thread-89, num=535
pool-1-thread-89, num=536
pool-1-thread-89, num=537
pool-1-thread-39, num=200
pool-1-thread-39, num=538
pool-1-thread-39, num=539
pool-1-thread-39, num=540
pool-1-thread-39, num=541
pool-1-thread-39, num=542
pool-1-thread-39, num=543
pool-1-thread-39, num=544
pool-1-thread-39, num=545
pool-1-thread-39, num=546
pool-1-thread-38, num=196
pool-1-thread-38, num=547
pool-1-thread-38, num=548
pool-1-thread-38, num=549
pool-1-thread-38, num=550
pool-1-thread-38, num=551
pool-1-thread-38, num=552
pool-1-thread-90, num=553
pool-1-thread-90, num=555
pool-1-thread-90, num=556
pool-1-thread-90, num=557
pool-1-thread-90, num=558
pool-1-thread-90, num=559
pool-1-thread-90, num=560
pool-1-thread-90, num=561
pool-1-thread-90, num=562
pool-1-thread-90, num=563
pool-1-thread-37, num=193
pool-1-thread-37, num=564
pool-1-thread-37, num=565
pool-1-thread-37, num=566
pool-1-thread-37, num=567
pool-1-thread-37, num=568
pool-1-thread-37, num=569
pool-1-thread-37, num=570
pool-1-thread-37, num=571
pool-1-thread-37, num=572
pool-1-thread-36, num=187
pool-1-thread-36, num=573
pool-1-thread-36, num=574
pool-1-thread-36, num=575
pool-1-thread-36, num=576
pool-1-thread-36, num=577
pool-1-thread-36, num=578
pool-1-thread-36, num=579
pool-1-thread-36, num=580
pool-1-thread-36, num=581
pool-1-thread-91, num=582
pool-1-thread-91, num=583
pool-1-thread-91, num=584
pool-1-thread-91, num=585
pool-1-thread-91, num=586
pool-1-thread-91, num=587
pool-1-thread-91, num=588
pool-1-thread-91, num=589
pool-1-thread-91, num=590
pool-1-thread-91, num=591
pool-1-thread-33, num=184
pool-1-thread-33, num=592
pool-1-thread-33, num=593
pool-1-thread-33, num=594
pool-1-thread-33, num=595
pool-1-thread-35, num=178
pool-1-thread-35, num=596
pool-1-thread-35, num=597
pool-1-thread-35, num=598
pool-1-thread-35, num=599
pool-1-thread-35, num=600
pool-1-thread-35, num=601
pool-1-thread-35, num=602
pool-1-thread-35, num=603
pool-1-thread-35, num=604
pool-1-thread-92, num=605
pool-1-thread-92, num=606
pool-1-thread-92, num=607
pool-1-thread-92, num=608
pool-1-thread-92, num=609
pool-1-thread-92, num=610
pool-1-thread-92, num=611
pool-1-thread-92, num=612
pool-1-thread-92, num=613
pool-1-thread-92, num=614
pool-1-thread-34, num=173
pool-1-thread-34, num=615
pool-1-thread-34, num=616
pool-1-thread-34, num=617
pool-1-thread-34, num=618
pool-1-thread-34, num=619
pool-1-thread-34, num=620
pool-1-thread-34, num=621
pool-1-thread-34, num=622
pool-1-thread-34, num=623
pool-1-thread-38, num=554
pool-1-thread-38, num=624
pool-1-thread-88, num=518
pool-1-thread-88, num=625
pool-1-thread-88, num=626
pool-1-thread-88, num=627
pool-1-thread-88, num=628
pool-1-thread-88, num=629
pool-1-thread-88, num=630
pool-1-thread-88, num=631
pool-1-thread-88, num=632
pool-1-thread-88, num=633
pool-1-thread-93, num=634
pool-1-thread-93, num=635
pool-1-thread-93, num=636
pool-1-thread-93, num=637
pool-1-thread-93, num=638
pool-1-thread-93, num=639
pool-1-thread-93, num=640
pool-1-thread-93, num=641
pool-1-thread-93, num=642
pool-1-thread-93, num=643
pool-1-thread-87, num=513
pool-1-thread-87, num=644
pool-1-thread-87, num=645
pool-1-thread-87, num=646
pool-1-thread-87, num=647
pool-1-thread-87, num=648
pool-1-thread-87, num=649
pool-1-thread-87, num=650
pool-1-thread-87, num=651
pool-1-thread-87, num=652
pool-1-thread-31, num=480
pool-1-thread-31, num=653
pool-1-thread-31, num=654
pool-1-thread-31, num=655
pool-1-thread-31, num=656
pool-1-thread-31, num=657
pool-1-thread-31, num=658
pool-1-thread-31, num=659
pool-1-thread-94, num=660
pool-1-thread-94, num=661
pool-1-thread-94, num=662
pool-1-thread-94, num=663
pool-1-thread-94, num=664
pool-1-thread-94, num=665
pool-1-thread-94, num=666
pool-1-thread-94, num=667
pool-1-thread-94, num=668
pool-1-thread-94, num=669
pool-1-thread-85, num=479
pool-1-thread-85, num=670
pool-1-thread-85, num=671
pool-1-thread-85, num=672
pool-1-thread-85, num=673
pool-1-thread-85, num=674
pool-1-thread-95, num=675
pool-1-thread-95, num=676
pool-1-thread-95, num=677
pool-1-thread-95, num=678
pool-1-thread-95, num=679
pool-1-thread-95, num=680
pool-1-thread-95, num=681
pool-1-thread-95, num=682
pool-1-thread-95, num=683
pool-1-thread-95, num=684
pool-1-thread-46, num=470
pool-1-thread-46, num=686
pool-1-thread-46, num=687
pool-1-thread-46, num=688
pool-1-thread-46, num=689
pool-1-thread-46, num=690
pool-1-thread-46, num=691
pool-1-thread-46, num=692
pool-1-thread-46, num=693
pool-1-thread-84, num=468
pool-1-thread-84, num=694
pool-1-thread-84, num=695
pool-1-thread-84, num=696
pool-1-thread-84, num=697
pool-1-thread-84, num=698
pool-1-thread-84, num=699
pool-1-thread-84, num=700
pool-1-thread-82, num=462
pool-1-thread-82, num=703
pool-1-thread-47, num=461
pool-1-thread-47, num=705
pool-1-thread-47, num=706
pool-1-thread-47, num=707
pool-1-thread-47, num=708
pool-1-thread-47, num=709
pool-1-thread-81, num=458
pool-1-thread-81, num=710
pool-1-thread-81, num=712
pool-1-thread-81, num=713
pool-1-thread-81, num=714
pool-1-thread-81, num=715
pool-1-thread-81, num=716
pool-1-thread-48, num=455
pool-1-thread-49, num=454
pool-1-thread-49, num=720
pool-1-thread-80, num=453
pool-1-thread-80, num=721
pool-1-thread-80, num=722
pool-1-thread-80, num=723
pool-1-thread-80, num=724
pool-1-thread-80, num=725
pool-1-thread-80, num=726
pool-1-thread-80, num=727
pool-1-thread-80, num=728
pool-1-thread-79, num=445
pool-1-thread-79, num=731
pool-1-thread-26, num=443
pool-1-thread-77, num=441
pool-1-thread-77, num=733
pool-1-thread-77, num=734
pool-1-thread-78, num=438
pool-1-thread-78, num=735
pool-1-thread-78, num=737
pool-1-thread-78, num=738
pool-1-thread-51, num=433
pool-1-thread-51, num=740
pool-1-thread-51, num=741
pool-1-thread-51, num=742
pool-1-thread-51, num=743
pool-1-thread-51, num=744
pool-1-thread-76, num=429
pool-1-thread-76, num=745
pool-1-thread-76, num=746
pool-1-thread-76, num=747
pool-1-thread-75, num=427
pool-1-thread-75, num=749
pool-1-thread-75, num=750
pool-1-thread-75, num=751
pool-1-thread-75, num=752
pool-1-thread-75, num=753
pool-1-thread-50, num=424
pool-1-thread-74, num=421
pool-1-thread-17, num=420
pool-1-thread-17, num=757
pool-1-thread-17, num=758
pool-1-thread-17, num=759
pool-1-thread-73, num=417
pool-1-thread-73, num=760
pool-1-thread-73, num=761
pool-1-thread-73, num=762
pool-1-thread-73, num=763
pool-1-thread-73, num=764
pool-1-thread-73, num=765
pool-1-thread-73, num=766
pool-1-thread-73, num=767
pool-1-thread-73, num=768
pool-1-thread-72, num=414
pool-1-thread-72, num=769
pool-1-thread-72, num=770
pool-1-thread-72, num=771
pool-1-thread-72, num=772
pool-1-thread-72, num=773
pool-1-thread-72, num=774
pool-1-thread-72, num=775
pool-1-thread-72, num=776
pool-1-thread-72, num=777
pool-1-thread-71, num=409
pool-1-thread-71, num=778
pool-1-thread-71, num=779
pool-1-thread-71, num=780
pool-1-thread-24, num=405
pool-1-thread-24, num=782
pool-1-thread-24, num=783
pool-1-thread-24, num=784
pool-1-thread-24, num=785
pool-1-thread-24, num=786
pool-1-thread-24, num=787
pool-1-thread-70, num=404
pool-1-thread-70, num=788
pool-1-thread-70, num=789
pool-1-thread-70, num=790
pool-1-thread-70, num=791
pool-1-thread-70, num=792
pool-1-thread-70, num=793
pool-1-thread-70, num=794
pool-1-thread-70, num=795
pool-1-thread-69, num=402
pool-1-thread-69, num=797
pool-1-thread-68, num=400
pool-1-thread-68, num=799
pool-1-thread-68, num=800
pool-1-thread-68, num=801
pool-1-thread-68, num=802
pool-1-thread-68, num=803
pool-1-thread-68, num=804
pool-1-thread-67, num=393
pool-1-thread-67, num=806
pool-1-thread-67, num=807
pool-1-thread-67, num=808
pool-1-thread-65, num=386
pool-1-thread-67, num=809
pool-1-thread-67, num=810
pool-1-thread-67, num=811
pool-1-thread-67, num=812
pool-1-thread-67, num=813
pool-1-thread-67, num=814
pool-1-thread-65, num=815
pool-1-thread-65, num=816
pool-1-thread-65, num=817
pool-1-thread-65, num=818
pool-1-thread-66, num=385
pool-1-thread-23, num=381
pool-1-thread-66, num=819
pool-1-thread-66, num=820
pool-1-thread-66, num=821
pool-1-thread-66, num=822
pool-1-thread-66, num=823
pool-1-thread-66, num=824
pool-1-thread-66, num=825
pool-1-thread-66, num=826
pool-1-thread-66, num=827
pool-1-thread-23, num=828
pool-1-thread-23, num=829
pool-1-thread-23, num=830
pool-1-thread-64, num=374
pool-1-thread-63, num=370
pool-1-thread-64, num=831
pool-1-thread-64, num=832
pool-1-thread-64, num=833
pool-1-thread-64, num=834
pool-1-thread-64, num=835
pool-1-thread-64, num=836
pool-1-thread-64, num=837
pool-1-thread-64, num=838
pool-1-thread-64, num=839
pool-1-thread-63, num=840
pool-1-thread-63, num=841
pool-1-thread-63, num=842
pool-1-thread-63, num=843
pool-1-thread-63, num=844
pool-1-thread-63, num=845
pool-1-thread-63, num=846
pool-1-thread-63, num=847
pool-1-thread-63, num=848
pool-1-thread-62, num=367
pool-1-thread-58, num=366
pool-1-thread-62, num=849
pool-1-thread-62, num=850
pool-1-thread-62, num=851
pool-1-thread-62, num=852
pool-1-thread-62, num=853
pool-1-thread-62, num=854
pool-1-thread-62, num=855
pool-1-thread-62, num=856
pool-1-thread-58, num=857
pool-1-thread-58, num=858
pool-1-thread-58, num=859
pool-1-thread-22, num=359
pool-1-thread-61, num=357
pool-1-thread-22, num=860
pool-1-thread-22, num=861
pool-1-thread-22, num=862
pool-1-thread-22, num=863
pool-1-thread-61, num=864
pool-1-thread-61, num=865
pool-1-thread-61, num=866
pool-1-thread-61, num=867
pool-1-thread-61, num=868
pool-1-thread-61, num=869
pool-1-thread-61, num=870
pool-1-thread-61, num=871
pool-1-thread-61, num=872
pool-1-thread-59, num=352
pool-1-thread-60, num=351
pool-1-thread-59, num=873
pool-1-thread-59, num=874
pool-1-thread-59, num=875
pool-1-thread-59, num=876
pool-1-thread-60, num=877
pool-1-thread-60, num=878
pool-1-thread-60, num=879
pool-1-thread-60, num=880
pool-1-thread-60, num=881
pool-1-thread-60, num=882
pool-1-thread-60, num=883
pool-1-thread-60, num=884
pool-1-thread-60, num=885
pool-1-thread-20, num=347
pool-1-thread-20, num=886
pool-1-thread-20, num=887
pool-1-thread-20, num=888
pool-1-thread-20, num=889
pool-1-thread-20, num=890
pool-1-thread-20, num=891
pool-1-thread-20, num=892
pool-1-thread-20, num=893
pool-1-thread-68, num=805
pool-1-thread-69, num=798
pool-1-thread-68, num=894
pool-1-thread-68, num=895
pool-1-thread-69, num=896
pool-1-thread-69, num=897
pool-1-thread-69, num=898
pool-1-thread-69, num=899
pool-1-thread-70, num=796
pool-1-thread-71, num=781
pool-1-thread-71, num=901
pool-1-thread-71, num=902
pool-1-thread-71, num=903
pool-1-thread-71, num=904
pool-1-thread-71, num=905
pool-1-thread-74, num=756
pool-1-thread-74, num=906
pool-1-thread-74, num=907
pool-1-thread-74, num=908
pool-1-thread-74, num=909
pool-1-thread-74, num=910
pool-1-thread-74, num=911
pool-1-thread-74, num=912
pool-1-thread-50, num=755
pool-1-thread-50, num=913
pool-1-thread-50, num=914
pool-1-thread-50, num=915
pool-1-thread-50, num=916
pool-1-thread-50, num=917
pool-1-thread-50, num=918
pool-1-thread-75, num=754
pool-1-thread-76, num=748
pool-1-thread-76, num=919
pool-1-thread-76, num=920
pool-1-thread-76, num=921
pool-1-thread-76, num=922
pool-1-thread-76, num=923
pool-1-thread-78, num=739
pool-1-thread-100, num=736
pool-1-thread-100, num=925
pool-1-thread-100, num=926
pool-1-thread-100, num=927
pool-1-thread-100, num=928
pool-1-thread-100, num=929
pool-1-thread-100, num=930
pool-1-thread-100, num=931
pool-1-thread-100, num=932
pool-1-thread-100, num=933
pool-1-thread-79, num=732
์“ฐ๋ ˆ๋“œ ์ฝœ ์ข…๋ฃŒ
pool-1-thread-79, num=934
pool-1-thread-79, num=935
pool-1-thread-79, num=936
pool-1-thread-79, num=937
pool-1-thread-79, num=938
pool-1-thread-80, num=730
pool-1-thread-99, num=729
pool-1-thread-99, num=939
pool-1-thread-99, num=940
pool-1-thread-99, num=941
pool-1-thread-99, num=942
pool-1-thread-99, num=943
pool-1-thread-99, num=944
pool-1-thread-99, num=945
pool-1-thread-99, num=946
pool-1-thread-99, num=947
pool-1-thread-48, num=719
pool-1-thread-48, num=948
pool-1-thread-48, num=949
pool-1-thread-48, num=950
pool-1-thread-48, num=951
pool-1-thread-48, num=952
pool-1-thread-48, num=953
pool-1-thread-81, num=717
pool-1-thread-81, num=954
pool-1-thread-81, num=955
pool-1-thread-98, num=718
pool-1-thread-98, num=956
pool-1-thread-98, num=957
pool-1-thread-98, num=958
pool-1-thread-98, num=959
pool-1-thread-98, num=960
pool-1-thread-98, num=961
pool-1-thread-98, num=962
pool-1-thread-98, num=963
pool-1-thread-98, num=964
pool-1-thread-97, num=711
pool-1-thread-97, num=965
pool-1-thread-97, num=966
pool-1-thread-97, num=967
pool-1-thread-97, num=968
pool-1-thread-97, num=969
pool-1-thread-97, num=970
pool-1-thread-97, num=971
pool-1-thread-97, num=972
pool-1-thread-97, num=973
pool-1-thread-82, num=704
pool-1-thread-82, num=974
pool-1-thread-82, num=975
pool-1-thread-82, num=976
pool-1-thread-82, num=977
pool-1-thread-82, num=978
pool-1-thread-82, num=979
pool-1-thread-84, num=702
pool-1-thread-84, num=980
pool-1-thread-96, num=701
pool-1-thread-96, num=981
pool-1-thread-96, num=982
pool-1-thread-96, num=983
pool-1-thread-96, num=984
pool-1-thread-96, num=985
pool-1-thread-96, num=986
pool-1-thread-96, num=987
pool-1-thread-96, num=988
pool-1-thread-96, num=989
pool-1-thread-85, num=685
pool-1-thread-85, num=990
pool-1-thread-85, num=991
pool-1-thread-85, num=992
pool-1-thread-78, num=924
pool-1-thread-78, num=993
pool-1-thread-78, num=994
pool-1-thread-78, num=995
pool-1-thread-78, num=996
pool-1-thread-69, num=900
pool-1-thread-69, num=997
pool-1-thread-69, num=998
executor has been terminated

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

 

์œ„ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ž์„ธํžˆ ํ™•์ธํ•ด๋ณด๋ฉด thread๋Š” thread-1 ~ thread-100 ๊นŒ์ง€ ์ด 100๊ฐœ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์‹คํ–‰์ด ๋œ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

์ด๋ฒˆ์—๋Š” corePoolSize๋ฅผ 1๋กœ ์„ค์ •์„ ํ•ด์„œ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. (๋”๋ณด๊ธฐ ํด๋ฆญํ•ด์„œ ๋ณด์„ธ์š”)

๋”๋ณด๊ธฐ

pool-1-thread-2, num=0
pool-1-thread-3, num=0
pool-1-thread-1, num=1
pool-1-thread-3, num=3
pool-1-thread-3, num=5
pool-1-thread-2, num=2
pool-1-thread-2, num=7
pool-1-thread-3, num=6
pool-1-thread-1, num=4
pool-1-thread-3, num=9
pool-1-thread-2, num=8
pool-1-thread-3, num=11
pool-1-thread-1, num=10
pool-1-thread-3, num=13
pool-1-thread-2, num=12
pool-1-thread-3, num=15
pool-1-thread-1, num=14
pool-1-thread-1, num=18
pool-1-thread-3, num=17
pool-1-thread-2, num=16
pool-1-thread-3, num=20
pool-1-thread-1, num=19
pool-1-thread-2, num=21
pool-1-thread-3, num=23
pool-1-thread-1, num=22
pool-1-thread-1, num=26
pool-1-thread-3, num=25
pool-1-thread-2, num=24
pool-1-thread-2, num=29
pool-1-thread-2, num=30
pool-1-thread-3, num=28
pool-1-thread-1, num=27
pool-1-thread-3, num=31
pool-1-thread-3, num=33
pool-1-thread-3, num=34
pool-1-thread-3, num=35
pool-1-thread-3, num=36
pool-1-thread-1, num=32
pool-1-thread-3, num=37
pool-1-thread-3, num=38
pool-1-thread-4, num=39
pool-1-thread-4, num=40
pool-1-thread-4, num=41
pool-1-thread-4, num=42
pool-1-thread-4, num=43
pool-1-thread-4, num=44
pool-1-thread-4, num=45
pool-1-thread-4, num=46
pool-1-thread-4, num=47
pool-1-thread-4, num=48
pool-1-thread-4, num=49
pool-1-thread-4, num=50
pool-1-thread-2, num=51
pool-1-thread-4, num=52
pool-1-thread-4, num=54
pool-1-thread-2, num=53
pool-1-thread-4, num=55
pool-1-thread-4, num=57
pool-1-thread-4, num=58
pool-1-thread-2, num=56
pool-1-thread-4, num=59
pool-1-thread-2, num=60
pool-1-thread-4, num=61
pool-1-thread-2, num=62
pool-1-thread-2, num=64
pool-1-thread-4, num=63
pool-1-thread-2, num=65
pool-1-thread-2, num=66
pool-1-thread-2, num=67
pool-1-thread-2, num=68
pool-1-thread-5, num=69
pool-1-thread-5, num=70
pool-1-thread-5, num=71
pool-1-thread-5, num=72
pool-1-thread-5, num=73
pool-1-thread-5, num=74
pool-1-thread-5, num=75
pool-1-thread-5, num=76
pool-1-thread-5, num=77
pool-1-thread-5, num=78
pool-1-thread-5, num=79
pool-1-thread-5, num=80
pool-1-thread-5, num=81
pool-1-thread-5, num=82
pool-1-thread-5, num=83
pool-1-thread-3, num=84
pool-1-thread-5, num=85
pool-1-thread-3, num=86
pool-1-thread-5, num=87
pool-1-thread-3, num=88
pool-1-thread-3, num=90
pool-1-thread-5, num=89
pool-1-thread-3, num=91
pool-1-thread-5, num=92
pool-1-thread-3, num=93
pool-1-thread-5, num=94
pool-1-thread-3, num=95
pool-1-thread-3, num=96
pool-1-thread-3, num=97
pool-1-thread-3, num=98
pool-1-thread-6, num=99
pool-1-thread-6, num=100
pool-1-thread-6, num=101
pool-1-thread-6, num=102
pool-1-thread-6, num=103
pool-1-thread-6, num=104
pool-1-thread-6, num=105
pool-1-thread-6, num=106
pool-1-thread-6, num=107
pool-1-thread-6, num=108
pool-1-thread-4, num=109
pool-1-thread-4, num=110
pool-1-thread-4, num=111
pool-1-thread-4, num=112
pool-1-thread-4, num=113
pool-1-thread-4, num=114
pool-1-thread-4, num=115
pool-1-thread-4, num=116
pool-1-thread-4, num=117
pool-1-thread-4, num=118
pool-1-thread-2, num=119
pool-1-thread-2, num=120
pool-1-thread-2, num=121
pool-1-thread-2, num=122
pool-1-thread-2, num=123
pool-1-thread-2, num=124
pool-1-thread-2, num=125
pool-1-thread-2, num=126
pool-1-thread-2, num=127
pool-1-thread-2, num=128
pool-1-thread-1, num=129
pool-1-thread-1, num=130
pool-1-thread-1, num=131
pool-1-thread-1, num=132
pool-1-thread-1, num=133
pool-1-thread-1, num=134
pool-1-thread-1, num=135
pool-1-thread-1, num=136
pool-1-thread-1, num=137
pool-1-thread-1, num=138
pool-1-thread-7, num=139
pool-1-thread-7, num=140
pool-1-thread-7, num=141
pool-1-thread-7, num=142
pool-1-thread-7, num=143
pool-1-thread-7, num=144
pool-1-thread-7, num=145
pool-1-thread-7, num=146
pool-1-thread-7, num=147
pool-1-thread-7, num=148
pool-1-thread-5, num=149
pool-1-thread-5, num=150
pool-1-thread-5, num=151
pool-1-thread-5, num=152
pool-1-thread-5, num=153
pool-1-thread-5, num=154
pool-1-thread-5, num=155
pool-1-thread-5, num=156
pool-1-thread-5, num=157
pool-1-thread-5, num=158
pool-1-thread-3, num=159
pool-1-thread-3, num=160
pool-1-thread-3, num=161
pool-1-thread-3, num=162
pool-1-thread-3, num=163
pool-1-thread-3, num=164
pool-1-thread-3, num=165
pool-1-thread-3, num=166
pool-1-thread-3, num=167
pool-1-thread-3, num=168
pool-1-thread-8, num=169
pool-1-thread-8, num=170
pool-1-thread-8, num=171
pool-1-thread-8, num=172
pool-1-thread-8, num=173
pool-1-thread-8, num=174
pool-1-thread-8, num=175
pool-1-thread-8, num=176
pool-1-thread-8, num=177
pool-1-thread-8, num=178
pool-1-thread-6, num=179
pool-1-thread-6, num=180
pool-1-thread-6, num=181
pool-1-thread-6, num=182
pool-1-thread-6, num=183
pool-1-thread-6, num=184
pool-1-thread-6, num=185
pool-1-thread-6, num=186
pool-1-thread-6, num=187
pool-1-thread-6, num=188
pool-1-thread-4, num=189
pool-1-thread-9, num=190
pool-1-thread-9, num=192
pool-1-thread-9, num=193
pool-1-thread-9, num=194
pool-1-thread-4, num=191
pool-1-thread-9, num=195
pool-1-thread-4, num=196
pool-1-thread-9, num=197
pool-1-thread-4, num=198
pool-1-thread-4, num=200
pool-1-thread-9, num=199
pool-1-thread-9, num=202
pool-1-thread-4, num=201
pool-1-thread-9, num=203
pool-1-thread-9, num=205
pool-1-thread-4, num=204
pool-1-thread-4, num=206
pool-1-thread-4, num=207
pool-1-thread-4, num=208
pool-1-thread-2, num=209
pool-1-thread-2, num=210
pool-1-thread-10, num=211
pool-1-thread-10, num=213
pool-1-thread-10, num=214
pool-1-thread-10, num=215
pool-1-thread-10, num=216
pool-1-thread-2, num=212
pool-1-thread-10, num=217
pool-1-thread-2, num=218
pool-1-thread-2, num=220
pool-1-thread-10, num=219
pool-1-thread-2, num=221
pool-1-thread-10, num=222
pool-1-thread-10, num=224
pool-1-thread-2, num=223
pool-1-thread-2, num=226
pool-1-thread-10, num=225
pool-1-thread-2, num=227
pool-1-thread-2, num=228
pool-1-thread-11, num=229
pool-1-thread-11, num=230
pool-1-thread-11, num=231
pool-1-thread-11, num=232
pool-1-thread-11, num=233
pool-1-thread-11, num=234
pool-1-thread-11, num=235
pool-1-thread-1, num=236
pool-1-thread-11, num=237
pool-1-thread-1, num=238
pool-1-thread-11, num=239
pool-1-thread-1, num=240
pool-1-thread-1, num=241
pool-1-thread-1, num=242
pool-1-thread-1, num=243
pool-1-thread-1, num=244
pool-1-thread-1, num=245
pool-1-thread-1, num=246
pool-1-thread-1, num=247
pool-1-thread-11, num=248
pool-1-thread-7, num=249
pool-1-thread-7, num=250
pool-1-thread-7, num=251
pool-1-thread-12, num=252
pool-1-thread-7, num=253
pool-1-thread-12, num=254
pool-1-thread-12, num=257
pool-1-thread-12, num=258
pool-1-thread-12, num=259
pool-1-thread-12, num=260
pool-1-thread-5, num=256
pool-1-thread-7, num=255
pool-1-thread-5, num=262
pool-1-thread-5, num=264
pool-1-thread-5, num=265
pool-1-thread-12, num=261
pool-1-thread-5, num=266
pool-1-thread-5, num=268
pool-1-thread-5, num=269
pool-1-thread-5, num=270
pool-1-thread-5, num=271
pool-1-thread-5, num=272
pool-1-thread-7, num=263
pool-1-thread-7, num=273
pool-1-thread-12, num=267
pool-1-thread-12, num=275
pool-1-thread-12, num=276
pool-1-thread-7, num=274
pool-1-thread-7, num=277
pool-1-thread-7, num=278
pool-1-thread-3, num=279
pool-1-thread-3, num=280
pool-1-thread-3, num=281
pool-1-thread-3, num=282
pool-1-thread-3, num=283
pool-1-thread-3, num=284
pool-1-thread-3, num=285
pool-1-thread-3, num=286
pool-1-thread-3, num=287
pool-1-thread-3, num=288
pool-1-thread-8, num=289
pool-1-thread-8, num=290
pool-1-thread-8, num=291
pool-1-thread-8, num=292
pool-1-thread-8, num=293
pool-1-thread-8, num=294
pool-1-thread-8, num=295
pool-1-thread-8, num=296
pool-1-thread-8, num=297
pool-1-thread-8, num=298
pool-1-thread-6, num=299
pool-1-thread-6, num=300
pool-1-thread-6, num=301
pool-1-thread-6, num=302
pool-1-thread-6, num=303
pool-1-thread-6, num=304
pool-1-thread-6, num=305
pool-1-thread-6, num=306
pool-1-thread-6, num=307
pool-1-thread-6, num=308
pool-1-thread-13, num=309
pool-1-thread-13, num=310
pool-1-thread-13, num=311
pool-1-thread-13, num=312
pool-1-thread-13, num=313
pool-1-thread-13, num=314
pool-1-thread-13, num=315
pool-1-thread-13, num=316
pool-1-thread-13, num=317
pool-1-thread-13, num=318
pool-1-thread-9, num=319
pool-1-thread-9, num=320
pool-1-thread-9, num=321
pool-1-thread-9, num=322
pool-1-thread-9, num=323
pool-1-thread-9, num=324
pool-1-thread-9, num=325
pool-1-thread-9, num=326
pool-1-thread-9, num=327
pool-1-thread-9, num=328
pool-1-thread-14, num=329
pool-1-thread-14, num=330
pool-1-thread-14, num=331
pool-1-thread-14, num=332
pool-1-thread-14, num=333
pool-1-thread-14, num=334
pool-1-thread-14, num=335
pool-1-thread-14, num=336
pool-1-thread-14, num=337
pool-1-thread-14, num=338
pool-1-thread-4, num=339
pool-1-thread-4, num=340
pool-1-thread-4, num=341
pool-1-thread-4, num=342
pool-1-thread-4, num=343
pool-1-thread-4, num=344
pool-1-thread-4, num=345
pool-1-thread-4, num=346
pool-1-thread-4, num=347
pool-1-thread-4, num=348
pool-1-thread-10, num=349
pool-1-thread-10, num=350
pool-1-thread-10, num=351
pool-1-thread-10, num=352
pool-1-thread-10, num=353
pool-1-thread-10, num=354
pool-1-thread-10, num=355
pool-1-thread-10, num=356
pool-1-thread-10, num=357
pool-1-thread-10, num=358
pool-1-thread-2, num=359
pool-1-thread-2, num=360
pool-1-thread-2, num=361
pool-1-thread-2, num=362
pool-1-thread-2, num=363
pool-1-thread-2, num=364
pool-1-thread-2, num=365
pool-1-thread-2, num=366
pool-1-thread-2, num=367
pool-1-thread-2, num=368
pool-1-thread-1, num=369
pool-1-thread-1, num=370
pool-1-thread-1, num=371
pool-1-thread-1, num=372
pool-1-thread-1, num=373
pool-1-thread-1, num=374
pool-1-thread-1, num=375
pool-1-thread-1, num=376
pool-1-thread-1, num=377
pool-1-thread-1, num=378
pool-1-thread-15, num=379
pool-1-thread-15, num=380
pool-1-thread-15, num=381
pool-1-thread-15, num=382
pool-1-thread-15, num=383
pool-1-thread-15, num=384
pool-1-thread-15, num=385
pool-1-thread-15, num=386
pool-1-thread-15, num=387
pool-1-thread-15, num=388
pool-1-thread-11, num=389
pool-1-thread-11, num=390
pool-1-thread-11, num=391
pool-1-thread-11, num=392
pool-1-thread-11, num=393
pool-1-thread-11, num=394
pool-1-thread-11, num=395
pool-1-thread-11, num=396
pool-1-thread-11, num=397
pool-1-thread-11, num=398
pool-1-thread-5, num=399
pool-1-thread-5, num=400
pool-1-thread-5, num=401
pool-1-thread-5, num=402
pool-1-thread-5, num=403
pool-1-thread-5, num=404
pool-1-thread-5, num=405
pool-1-thread-5, num=406
pool-1-thread-5, num=407
pool-1-thread-5, num=408
pool-1-thread-12, num=409
pool-1-thread-12, num=410
pool-1-thread-12, num=411
pool-1-thread-12, num=412
pool-1-thread-12, num=413
pool-1-thread-12, num=414
pool-1-thread-12, num=415
pool-1-thread-12, num=416
pool-1-thread-12, num=417
pool-1-thread-12, num=418
pool-1-thread-7, num=419
pool-1-thread-7, num=420
pool-1-thread-7, num=421
pool-1-thread-7, num=422
pool-1-thread-7, num=423
pool-1-thread-7, num=424
pool-1-thread-7, num=425
pool-1-thread-7, num=426
pool-1-thread-7, num=427
pool-1-thread-7, num=428
pool-1-thread-16, num=429
pool-1-thread-16, num=430
pool-1-thread-16, num=431
pool-1-thread-16, num=432
pool-1-thread-16, num=433
pool-1-thread-16, num=434
pool-1-thread-16, num=435
pool-1-thread-16, num=436
pool-1-thread-16, num=437
pool-1-thread-16, num=438
pool-1-thread-3, num=439
pool-1-thread-3, num=440
pool-1-thread-3, num=441
pool-1-thread-3, num=442
pool-1-thread-3, num=443
pool-1-thread-3, num=444
pool-1-thread-3, num=445
pool-1-thread-3, num=446
pool-1-thread-3, num=447
pool-1-thread-3, num=448
pool-1-thread-8, num=449
pool-1-thread-8, num=450
pool-1-thread-8, num=451
pool-1-thread-8, num=452
pool-1-thread-8, num=453
pool-1-thread-8, num=454
pool-1-thread-8, num=455
pool-1-thread-8, num=456
pool-1-thread-8, num=457
pool-1-thread-8, num=458
pool-1-thread-6, num=459
pool-1-thread-6, num=460
pool-1-thread-6, num=461
pool-1-thread-6, num=462
pool-1-thread-6, num=463
pool-1-thread-6, num=464
pool-1-thread-6, num=465
pool-1-thread-6, num=466
pool-1-thread-6, num=467
pool-1-thread-6, num=468
pool-1-thread-6, num=469
pool-1-thread-6, num=470
pool-1-thread-6, num=471
pool-1-thread-6, num=472
pool-1-thread-6, num=473
pool-1-thread-6, num=474
pool-1-thread-6, num=475
pool-1-thread-6, num=476
pool-1-thread-6, num=477
pool-1-thread-6, num=478
pool-1-thread-9, num=479
pool-1-thread-9, num=480
pool-1-thread-9, num=481
pool-1-thread-9, num=482
pool-1-thread-9, num=483
pool-1-thread-9, num=484
pool-1-thread-9, num=485
pool-1-thread-9, num=486
pool-1-thread-9, num=487
pool-1-thread-9, num=488
pool-1-thread-17, num=489
pool-1-thread-17, num=490
pool-1-thread-17, num=491
pool-1-thread-17, num=492
pool-1-thread-17, num=493
pool-1-thread-17, num=494
pool-1-thread-17, num=495
pool-1-thread-17, num=496
pool-1-thread-17, num=497
pool-1-thread-17, num=498
pool-1-thread-14, num=499
pool-1-thread-14, num=500
pool-1-thread-14, num=501
pool-1-thread-14, num=502
pool-1-thread-14, num=503
pool-1-thread-14, num=504
pool-1-thread-14, num=505
pool-1-thread-14, num=506
pool-1-thread-14, num=507
pool-1-thread-14, num=508
pool-1-thread-4, num=509
pool-1-thread-4, num=510
pool-1-thread-4, num=511
pool-1-thread-4, num=512
pool-1-thread-4, num=513
pool-1-thread-4, num=514
pool-1-thread-4, num=515
pool-1-thread-4, num=516
pool-1-thread-4, num=517
pool-1-thread-4, num=518
pool-1-thread-10, num=519
pool-1-thread-10, num=520
pool-1-thread-10, num=521
pool-1-thread-10, num=522
pool-1-thread-10, num=523
pool-1-thread-10, num=524
pool-1-thread-10, num=525
pool-1-thread-10, num=526
pool-1-thread-10, num=527
pool-1-thread-10, num=528
pool-1-thread-2, num=529
pool-1-thread-2, num=530
pool-1-thread-2, num=531
pool-1-thread-2, num=532
pool-1-thread-2, num=533
pool-1-thread-2, num=534
pool-1-thread-2, num=535
pool-1-thread-2, num=536
pool-1-thread-2, num=537
pool-1-thread-2, num=538
pool-1-thread-1, num=539
pool-1-thread-1, num=540
pool-1-thread-1, num=541
pool-1-thread-1, num=542
pool-1-thread-1, num=543
pool-1-thread-1, num=544
pool-1-thread-1, num=545
pool-1-thread-1, num=546
pool-1-thread-1, num=547
pool-1-thread-1, num=548
pool-1-thread-15, num=549
pool-1-thread-15, num=550
pool-1-thread-15, num=551
pool-1-thread-15, num=552
pool-1-thread-15, num=553
pool-1-thread-15, num=554
pool-1-thread-15, num=555
pool-1-thread-15, num=556
pool-1-thread-15, num=557
pool-1-thread-15, num=558
pool-1-thread-18, num=559
pool-1-thread-18, num=560
pool-1-thread-18, num=561
pool-1-thread-18, num=562
pool-1-thread-18, num=563
pool-1-thread-18, num=564
pool-1-thread-18, num=565
pool-1-thread-18, num=566
pool-1-thread-18, num=567
pool-1-thread-18, num=568
pool-1-thread-11, num=569
pool-1-thread-11, num=570
pool-1-thread-11, num=571
pool-1-thread-11, num=572
pool-1-thread-11, num=573
pool-1-thread-11, num=574
pool-1-thread-11, num=575
pool-1-thread-11, num=576
pool-1-thread-11, num=577
pool-1-thread-11, num=578
pool-1-thread-5, num=579
pool-1-thread-5, num=580
pool-1-thread-5, num=581
pool-1-thread-5, num=582
pool-1-thread-5, num=583
pool-1-thread-5, num=584
pool-1-thread-5, num=585
pool-1-thread-5, num=586
pool-1-thread-5, num=587
pool-1-thread-5, num=588
pool-1-thread-12, num=589
pool-1-thread-12, num=590
pool-1-thread-12, num=591
pool-1-thread-12, num=592
pool-1-thread-12, num=593
pool-1-thread-12, num=594
pool-1-thread-12, num=595
pool-1-thread-12, num=596
pool-1-thread-12, num=597
pool-1-thread-12, num=598
pool-1-thread-7, num=599
pool-1-thread-7, num=600
pool-1-thread-7, num=601
pool-1-thread-7, num=602
pool-1-thread-7, num=603
pool-1-thread-7, num=604
pool-1-thread-7, num=605
pool-1-thread-7, num=606
pool-1-thread-7, num=607
pool-1-thread-7, num=608
pool-1-thread-19, num=609
pool-1-thread-19, num=610
pool-1-thread-19, num=611
pool-1-thread-19, num=612
pool-1-thread-19, num=613
pool-1-thread-19, num=614
pool-1-thread-19, num=615
pool-1-thread-19, num=616
pool-1-thread-19, num=617
pool-1-thread-19, num=618
pool-1-thread-16, num=619
pool-1-thread-16, num=620
pool-1-thread-16, num=621
pool-1-thread-16, num=622
pool-1-thread-16, num=623
pool-1-thread-16, num=624
pool-1-thread-16, num=625
pool-1-thread-16, num=626
pool-1-thread-16, num=627
pool-1-thread-16, num=628
pool-1-thread-3, num=629
pool-1-thread-3, num=630
pool-1-thread-3, num=631
pool-1-thread-3, num=632
pool-1-thread-3, num=633
pool-1-thread-3, num=634
pool-1-thread-3, num=635
pool-1-thread-3, num=636
pool-1-thread-3, num=637
pool-1-thread-3, num=638
pool-1-thread-8, num=639
pool-1-thread-8, num=640
pool-1-thread-8, num=641
pool-1-thread-8, num=642
pool-1-thread-8, num=643
pool-1-thread-8, num=644
pool-1-thread-8, num=645
pool-1-thread-8, num=646
pool-1-thread-8, num=647
pool-1-thread-8, num=648
pool-1-thread-6, num=649
pool-1-thread-6, num=650
pool-1-thread-6, num=651
pool-1-thread-6, num=652
pool-1-thread-6, num=653
pool-1-thread-6, num=654
pool-1-thread-6, num=655
pool-1-thread-6, num=656
pool-1-thread-6, num=657
pool-1-thread-6, num=658
pool-1-thread-13, num=659
pool-1-thread-13, num=660
pool-1-thread-13, num=661
pool-1-thread-13, num=662
pool-1-thread-13, num=663
pool-1-thread-13, num=664
pool-1-thread-13, num=665
pool-1-thread-13, num=666
pool-1-thread-13, num=667
pool-1-thread-13, num=668
pool-1-thread-9, num=669
pool-1-thread-9, num=670
pool-1-thread-9, num=671
pool-1-thread-9, num=672
pool-1-thread-9, num=673
pool-1-thread-9, num=674
pool-1-thread-9, num=675
pool-1-thread-9, num=676
pool-1-thread-9, num=677
pool-1-thread-9, num=678
pool-1-thread-20, num=679
pool-1-thread-20, num=680
pool-1-thread-20, num=681
pool-1-thread-20, num=682
pool-1-thread-20, num=683
pool-1-thread-20, num=684
pool-1-thread-20, num=685
pool-1-thread-20, num=686
pool-1-thread-20, num=687
pool-1-thread-20, num=688
pool-1-thread-17, num=689
pool-1-thread-17, num=690
pool-1-thread-17, num=691
pool-1-thread-17, num=692
pool-1-thread-17, num=693
pool-1-thread-17, num=694
pool-1-thread-17, num=695
pool-1-thread-17, num=696
pool-1-thread-17, num=697
pool-1-thread-17, num=698
pool-1-thread-14, num=699
pool-1-thread-14, num=700
pool-1-thread-14, num=701
pool-1-thread-14, num=702
pool-1-thread-14, num=703
pool-1-thread-14, num=704
pool-1-thread-14, num=705
pool-1-thread-14, num=706
pool-1-thread-14, num=707
pool-1-thread-14, num=708
pool-1-thread-4, num=709
pool-1-thread-4, num=710
pool-1-thread-4, num=711
pool-1-thread-4, num=712
pool-1-thread-4, num=713
pool-1-thread-4, num=714
pool-1-thread-4, num=715
pool-1-thread-4, num=716
pool-1-thread-4, num=717
pool-1-thread-4, num=718
pool-1-thread-10, num=719
pool-1-thread-10, num=720
pool-1-thread-10, num=721
pool-1-thread-10, num=722
pool-1-thread-10, num=723
pool-1-thread-10, num=724
pool-1-thread-10, num=725
pool-1-thread-10, num=726
pool-1-thread-10, num=727
pool-1-thread-10, num=728
pool-1-thread-2, num=729
pool-1-thread-2, num=730
pool-1-thread-2, num=731
pool-1-thread-2, num=732
pool-1-thread-2, num=733
pool-1-thread-2, num=734
pool-1-thread-2, num=735
pool-1-thread-2, num=736
pool-1-thread-2, num=737
pool-1-thread-2, num=738
pool-1-thread-1, num=739
pool-1-thread-1, num=740
pool-1-thread-1, num=741
pool-1-thread-1, num=742
pool-1-thread-1, num=743
pool-1-thread-1, num=744
pool-1-thread-1, num=745
pool-1-thread-1, num=746
pool-1-thread-1, num=747
pool-1-thread-1, num=748
pool-1-thread-21, num=749
pool-1-thread-21, num=750
pool-1-thread-21, num=751
pool-1-thread-21, num=752
pool-1-thread-21, num=753
pool-1-thread-21, num=754
pool-1-thread-21, num=755
pool-1-thread-21, num=756
pool-1-thread-21, num=757
pool-1-thread-21, num=758
pool-1-thread-15, num=759
pool-1-thread-15, num=760
pool-1-thread-15, num=761
pool-1-thread-15, num=762
pool-1-thread-15, num=763
pool-1-thread-15, num=764
pool-1-thread-15, num=765
pool-1-thread-15, num=766
pool-1-thread-15, num=767
pool-1-thread-15, num=768
pool-1-thread-18, num=769
pool-1-thread-18, num=770
pool-1-thread-18, num=771
pool-1-thread-18, num=772
pool-1-thread-18, num=773
pool-1-thread-18, num=774
pool-1-thread-18, num=775
pool-1-thread-18, num=776
pool-1-thread-18, num=777
pool-1-thread-18, num=778
pool-1-thread-11, num=779
pool-1-thread-11, num=780
pool-1-thread-11, num=781
pool-1-thread-11, num=782
pool-1-thread-11, num=783
pool-1-thread-11, num=784
pool-1-thread-11, num=785
pool-1-thread-11, num=786
pool-1-thread-11, num=787
pool-1-thread-11, num=788
pool-1-thread-22, num=789
pool-1-thread-22, num=790
pool-1-thread-22, num=791
pool-1-thread-22, num=792
pool-1-thread-22, num=793
pool-1-thread-22, num=794
pool-1-thread-22, num=795
pool-1-thread-22, num=796
pool-1-thread-22, num=797
pool-1-thread-22, num=798
pool-1-thread-5, num=799
pool-1-thread-5, num=800
pool-1-thread-5, num=801
pool-1-thread-5, num=802
pool-1-thread-5, num=803
pool-1-thread-5, num=804
pool-1-thread-5, num=805
pool-1-thread-5, num=806
pool-1-thread-5, num=807
pool-1-thread-5, num=808
pool-1-thread-23, num=809
pool-1-thread-23, num=810
pool-1-thread-23, num=811
pool-1-thread-23, num=812
pool-1-thread-23, num=813
pool-1-thread-23, num=814
pool-1-thread-23, num=815
pool-1-thread-23, num=816
pool-1-thread-23, num=817
pool-1-thread-23, num=818
pool-1-thread-12, num=819
pool-1-thread-12, num=820
pool-1-thread-12, num=821
pool-1-thread-12, num=822
pool-1-thread-12, num=823
pool-1-thread-12, num=824
pool-1-thread-12, num=825
pool-1-thread-12, num=826
pool-1-thread-12, num=827
pool-1-thread-12, num=828
pool-1-thread-7, num=829
pool-1-thread-7, num=830
pool-1-thread-7, num=831
pool-1-thread-7, num=832
pool-1-thread-7, num=833
pool-1-thread-7, num=834
pool-1-thread-7, num=835
pool-1-thread-7, num=836
pool-1-thread-7, num=837
pool-1-thread-7, num=838
pool-1-thread-24, num=839
pool-1-thread-24, num=840
pool-1-thread-24, num=841
pool-1-thread-24, num=842
pool-1-thread-24, num=843
pool-1-thread-24, num=844
pool-1-thread-24, num=845
pool-1-thread-24, num=846
pool-1-thread-24, num=847
pool-1-thread-24, num=848
pool-1-thread-24, num=849
pool-1-thread-24, num=850
pool-1-thread-24, num=851
pool-1-thread-24, num=852
pool-1-thread-24, num=853
pool-1-thread-24, num=854
pool-1-thread-24, num=855
pool-1-thread-24, num=856
pool-1-thread-24, num=857
pool-1-thread-24, num=858
pool-1-thread-19, num=859
pool-1-thread-19, num=860
pool-1-thread-19, num=861
pool-1-thread-19, num=862
pool-1-thread-19, num=863
pool-1-thread-19, num=864
pool-1-thread-19, num=865
pool-1-thread-19, num=866
pool-1-thread-19, num=867
pool-1-thread-19, num=868
pool-1-thread-3, num=869
pool-1-thread-3, num=870
pool-1-thread-3, num=871
pool-1-thread-3, num=872
pool-1-thread-3, num=873
pool-1-thread-3, num=874
pool-1-thread-3, num=875
pool-1-thread-3, num=876
pool-1-thread-3, num=877
pool-1-thread-3, num=878
pool-1-thread-25, num=879
pool-1-thread-25, num=880
pool-1-thread-25, num=881
pool-1-thread-25, num=882
pool-1-thread-25, num=883
pool-1-thread-25, num=884
pool-1-thread-25, num=885
pool-1-thread-25, num=886
pool-1-thread-25, num=887
pool-1-thread-25, num=888
pool-1-thread-8, num=889
pool-1-thread-8, num=890
pool-1-thread-8, num=891
pool-1-thread-8, num=892
pool-1-thread-8, num=893
pool-1-thread-8, num=894
pool-1-thread-8, num=895
pool-1-thread-8, num=896
pool-1-thread-8, num=897
pool-1-thread-8, num=898
pool-1-thread-6, num=899
pool-1-thread-6, num=900
pool-1-thread-6, num=901
pool-1-thread-6, num=902
pool-1-thread-6, num=903
pool-1-thread-6, num=904
pool-1-thread-6, num=905
pool-1-thread-6, num=906
pool-1-thread-6, num=907
pool-1-thread-6, num=908
pool-1-thread-13, num=909
pool-1-thread-13, num=910
pool-1-thread-13, num=911
pool-1-thread-26, num=912
pool-1-thread-26, num=914
pool-1-thread-26, num=915
pool-1-thread-26, num=916
pool-1-thread-26, num=917
pool-1-thread-26, num=918
pool-1-thread-26, num=919
pool-1-thread-26, num=920
pool-1-thread-26, num=921
pool-1-thread-26, num=922
pool-1-thread-13, num=913
pool-1-thread-13, num=923
pool-1-thread-13, num=924
pool-1-thread-13, num=925
pool-1-thread-13, num=926
pool-1-thread-13, num=927
pool-1-thread-13, num=928
pool-1-thread-9, num=929
pool-1-thread-9, num=930
pool-1-thread-9, num=931
pool-1-thread-9, num=932
pool-1-thread-9, num=933
pool-1-thread-9, num=934
pool-1-thread-9, num=935
pool-1-thread-9, num=936
pool-1-thread-9, num=937
pool-1-thread-9, num=938
pool-1-thread-20, num=939
pool-1-thread-20, num=940
pool-1-thread-20, num=941
pool-1-thread-20, num=942
pool-1-thread-20, num=943
pool-1-thread-20, num=944
pool-1-thread-20, num=945
pool-1-thread-20, num=946
pool-1-thread-20, num=947
pool-1-thread-20, num=948
pool-1-thread-17, num=949
pool-1-thread-17, num=950
pool-1-thread-17, num=951
pool-1-thread-17, num=952
pool-1-thread-17, num=953
pool-1-thread-17, num=954
pool-1-thread-17, num=955
pool-1-thread-17, num=956
pool-1-thread-17, num=957
pool-1-thread-17, num=958
pool-1-thread-27, num=959
pool-1-thread-27, num=960
pool-1-thread-27, num=961
pool-1-thread-27, num=962
pool-1-thread-27, num=963
pool-1-thread-27, num=964
pool-1-thread-27, num=965
pool-1-thread-27, num=966
pool-1-thread-27, num=967
pool-1-thread-27, num=968
pool-1-thread-14, num=969
pool-1-thread-14, num=970
pool-1-thread-14, num=971
pool-1-thread-14, num=972
pool-1-thread-14, num=973
pool-1-thread-14, num=974
pool-1-thread-14, num=975
pool-1-thread-14, num=976
pool-1-thread-14, num=977
pool-1-thread-14, num=978
pool-1-thread-4, num=979
pool-1-thread-4, num=980
pool-1-thread-4, num=981
pool-1-thread-4, num=982
pool-1-thread-4, num=983
pool-1-thread-4, num=984
pool-1-thread-4, num=985
pool-1-thread-4, num=986
pool-1-thread-4, num=987
pool-1-thread-4, num=988
pool-1-thread-10, num=989
pool-1-thread-10, num=990
pool-1-thread-10, num=991
pool-1-thread-10, num=992
pool-1-thread-10, num=993
pool-1-thread-10, num=994
pool-1-thread-10, num=995
pool-1-thread-10, num=996
pool-1-thread-10, num=997
pool-1-thread-10, num=998
์“ฐ๋ ˆ๋“œ ์ฝœ ์ข…๋ฃŒ
executor has been terminated

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

 

thread๊ฐ€ 1~27 ๊นŒ์ง€ 27๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์‹คํ–‰์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์™œ ์ด๋Ÿฐ ๊ฑธ๊นŒ์š”?

corePoolSize๋ฅผ 1๋กœ ์ฃผ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ๋ ˆ๋“œํ’€์€ 1๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋กœ ์‹œ์ž‘์„ ํ•˜๊ฒŒ๋˜๊ณ  ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋๋‚˜๊ธฐ ์ „์— ์ƒˆ๋กœ์šด task์˜ ์‹คํ–‰ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ƒˆ๋กœ์šด task์˜ ์‹คํ–‰ ์š”์ฒญ์ด ์ด์ „ task๊ฐ€ ์ข…๋ฃŒ๋œ ์ดํ›„์— ๋“ค์–ด์˜ค๊ฒŒ๋˜๋ฉด ์ƒˆ๋กœ์šด ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์“ฐ๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜๋Š” ์žฅ์ ์ด์ฃ . ์“ฐ๋ ˆ๋“œ ํ’€์— ํ•„์š”ํ•œ ๊ฐœ์ˆ˜๋งŒํผ์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ถˆํ•„์š”ํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ฌ์œผ๋กœ์จ ์†Œ๋ชจ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€ ThreadPoolExecutor๋ฅผ ํ™œ์šฉํ•œ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•œ ํฌ์ŠคํŒ…์„ ๋งˆ์นฉ๋‹ˆ๋‹ค.

 

Reference: ์˜ค๋ผํด Java 8 ๊ณต์‹ ๋ฌธ์„œ

 

์ถ”๊ฐ€๋กœ ํ˜„์žฌ Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•œ Task์—์„œ num ๋ณ€์ˆ˜๋ฅผ 1์”ฉ ์ฆ๊ฐ€ํ•ด์„œ ์ถœ๋ ฅํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค๋งŒ, ์‹ค์ œ๋กœ ๋งˆ์ง€๋ง‰ ์ˆซ์ž๋ฅผ ๋ณด๋ฉด 999๊ฐ€ ์•„๋‹Œ 998์ด ์ถœ๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ํ•ด๋ณด๋ฉด ๊ฐ€์žฅ ํฐ ์ˆซ์ž๊ฐ€ 99X~999๊ฐ€ ๋žœ๋คํ•˜๊ฒŒ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ num์ด๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ณต์œ ํ•˜๋Š”๋ฐ ๊ฐ’์„ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์˜คํผ๋ ˆ์ด์…˜์ด thread safeํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์žˆ์ง€ ์•Š์Œ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด volatileํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ

์ž๋ฐ”์—์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ๊ฐ„๋žตํ•˜๊ฒŒ ํฌ์ŠคํŒ…ํ•ฉ๋‹ˆ๋‹ค.

 

์ž๋ฐ”์—์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ 2๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ๋Š” Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ Thread ์ƒ์„ฑ์ž๋กœ ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด๊ณ ,

๋‘ ๋ฒˆ์งธ๋Š” ์ง์ ‘ Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์šฐ์„  ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์œผ๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ  ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        Runnable task = new Task();
        Thread thread = new Thread(task);
        thread.start();
    }
    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
        	for(int i = 0; i < 10; i++) {
	            System.out.println(num++);
            }
        }
    }

 

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ์ด ๋ฉ๋‹ˆ๋‹ค.

	0
	1
	2
	3
	4
	5
	6
	7
	8
	9

 

์ด๋ฒˆ์—๋Š” Thread ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜์—ฌ ๋™์ผํ•œ ์ž‘์—…(task)์„ ํ•˜๋„๋ก ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        ThreadTask task = new ThreadTask();
        task.run();        
    }
    static class ThreadTask extends Thread {

        int num = 0;

        @Override
        public void run() {
        	for(int i = 0; i < 10; i++) {
	            System.out.println(num++);
    	    }
        }
    }

 

์‹คํ–‰ํ•˜๋ฉด Runnable๋กœ ๊ตฌํ˜„ํ–ˆ์„ ๋•Œ์™€ ๋™์ผํ•˜๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ์ด ๋ฉ๋‹ˆ๋‹ค.

	0
	1
	2
	3
	4
	5
	6
	7
	8
	9

 

์ฐธ๊ณ ๋กœ ์‹ค์ œ Thread ํด๋ž˜์Šค๋ฅผ ์—ด์–ด๋ณด๋ฉด Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ implementํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

public class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;
.
.
.

 

๊ทธ๋Ÿผ ์ด๋ฒˆ์—๋Š” ์“ฐ๋ ˆ๋“œ ๋‘ ๊ฐœ๋ฅผ ๋™์‹œ์— ๋Œ๋ ค๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        Runnable task = new Task();

        Thread thread1 = new Thread(task);
        thread1.start();
        System.out.println("thread 1 executed.");

        Thread thread2 = new Thread(task);
        thread2.start();
        System.out.println("thread 2 executed.");

        System.out.println("์“ฐ๋ ˆ๋“œ ์ฝœ ์ข…๋ฃŒ");
    }

    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", num=" + num++);
            }
        }
    }

 

์ค‘๊ฐ„์ค‘๊ฐ„์— ์–ด๋–ป๊ฒŒ ์‹คํ–‰์ด ๋˜๋Š”์ง€ ํ™•์ธ์„ ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ System.out.println์œผ๋กœ ๋กœ๊น…์„ ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

thread 1 executed.
Thread-0, num=0
Thread-0, num=1
Thread-0, num=2
Thread-0, num=3
Thread-0, num=4
Thread-0, num=5
thread 2 executed.
์“ฐ๋ ˆ๋“œ ์ฝœ ์ข…๋ฃŒ
Thread-0, num=6
Thread-1, num=7
Thread-1, num=9
Thread-0, num=8
Thread-1, num=10
Thread-0, num=11
Thread-1, num=12
Thread-1, num=13
Thread-1, num=14
Thread-1, num=16
Thread-1, num=17
Thread-1, num=18
Thread-1, num=19
Thread-0, num=15

BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date

 

์œ„ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋จผ์ € ์‹œ์ž‘๋˜์ง€๋งŒ "task1 executed"๊ฐ€ ๋จผ์ € ์ถœ๋ ฅ์ด ๋˜์—ˆ๊ณ  ๊ทธ ๋’ค์— ์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ์ธ Thread-0์ด ์ถœ๋ ฅ์„ ์‹œ์ž‘ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ค‘๊ฐ„์— "task2 executed"๊ฐ€ ์ถœ๋ ฅ๋œ ๊ฑธ ๋ณด๋‹ˆ ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰์ด ๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์ฃ . ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๋Š” Thread-1 ์ด๋ฉฐ ์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ผ์„ ๋งˆ์น˜๊ธฐ ์ „์— ์‹œ์ž‘๋˜์–ด "Thread-1, num=0"์„ ์ถœ๋ ฅํ•œ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค(main ํ”„๋กœ์„ธ์Šค) ์•ˆ์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—…์„ ๋™์‹œ์— ๋‚˜๋ˆ„์–ด ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์ด ์“ฐ๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค.

์“ฐ๋ ˆ๋“œ๋กœ ์ž‘์—…์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํŠน์ง•๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์ž‘์—…์„ ์™„๋ฃŒํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ด ์†Œ์š” ์‹œ๊ฐ„์ด ์ค„์–ด๋“ ๋‹ค. (๋ฉ”์ธ์“ฐ๋ ˆ๋“œ 1๊ฐœ๋กœ ์ž‘์—…ํ–ˆ์„ ๋•Œ์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ)
  • ๋จผ์ € ์‹œ์ž‘ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•ญ์ƒ ๋จผ์ € ์ผ์„ ๋๋‚ด์ง€๋Š” ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ, ์ž‘์—…์˜ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•  ๋•Œ์—๋Š” ์“ฐ๋ ˆ๋“œ๋กœ ๋‚˜๋ˆ„์–ด ์ฒ˜๋ฆฌํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

 

์ž, ์ด์ œ ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ๋กœ 10์‹œ๊ฐ„ ๊ฑธ๋ฆด ์ผ์„ 100๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋Œ๋ ค์„œ 10๋ถ„๋งŒ์— ๋๋‚ด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

์“ฐ๋ ˆ๋“œ๋ฅผ 100๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๋ฐ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฌด์‹ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ• ๊นŒ์š”?

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        Thread thread3 = new Thread(task);
        Thread thread4 = new Thread(task);
        Thread thread5 = new Thread(task);
        .
        .
        .

 

์•„๋‹™๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•ด์•ผ๋˜๋ฉด ์“ฐ๋ ˆ๋“œ ๋งŒ๋“ค๋‹ค๊ฐ€ ํ‡ด๊ทผํ•ด์•ผ๋ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์—์„œ๋Š” java.util.concurrentํŒจํ‚ค์ง€์— ๋™์‹œ์ž‘์—…์„ ์œ„ํ•ด ์œ ์šฉํ•œ ํด๋ž˜์Šค๋“ค์„ ๋ชจ์•„๋†จ๋Š”๋ฐ ๊ทธ์ค‘์— ThreadPoolExecutor๋ผ๋Š” ๋…€์„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋…€์„์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‘ ์„ธ ์ค„์ด๋ฉด 100๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋Œ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ฃ .

ThreadPoolExecutor์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋ ค๋ฉด ํฌ์ŠคํŠธ๊ฐ€ ๊ธธ์–ด์ง€๋‹ˆ ThreadPoolExecutor๋ฅผ ์ด์šฉํ•œ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„์„œ ๊ณ„์† ์ด์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์‹œ ๋กœ๊น… uuid ์„ค์ •

ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ํ™˜๊ฒฝ์—์„œ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๋Š”๋ฐ ๊ฐ ์“ฐ๋ ˆ๋“œ์— uuid ์„ค์ •์ด ์•ˆ๋˜์–ด ์žˆ์–ด ๋กœ๊ทธ์ƒ์œผ๋กœ ํ™•์ธ์ด ๋ถˆ๊ฐ€ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ฒผ๋‹ค. ๊ธฐ์กด์—๋Š” ์ž˜ ๋˜๊ณ  ์žˆ์—ˆ๋˜ ๊ฒƒ์ด์—ˆ๊ณ  ๋ญ”๊ฐ€ ์ˆ˜์ •์ž‘์—…์„ ํ•˜๋ฉด์„œ ๋นผ๋œจ๋ฆฐ ๊ฒƒ ๊ฐ™์•„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋“ค์˜ ์„ค์ •์„ ๋ณด๋‹ค๊ฐ€ TaskDecorator๋ฅผ ๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

 

package com.keichee;

import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;

import java.util.Map;

public class LoggingTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable task) {
        Map<String, String> callerThreadContext = MDC.getCopyOfContextMap();
        return () -> {
            MDC.setContextMap(callerThreadContext);
            task.run();
        };
    }
}

 

LoggingTaskDecorator๋Š” TaskDecorator๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š”๋ฐ decorate(Runnable task) ๋ฉ”์„œ๋“œ๋งŒ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ TaskDecorator๋Š” ์–ด๋–ค task(์ž‘์—…)์„ ๊พธ๋ฉฐ์ค€๋‹ค๋Š” ์˜๋ฏธ๋กœ ์ง€์–ด์ง„ ์ด๋ฆ„์ด๋ฉฐ ์Šคํ”„๋ง์˜ ์ฝ”์–ด ํŒจํ‚ค์ง€์— ๋“ค์–ด์žˆ์„ ๋งŒํผ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋…€์„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ์Šคํ”„๋ง ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด TaskDecorator๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค๋ช…์ด ๋˜์–ด์žˆ๋‹ค.

 

Functional Interface : This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.@FunctionalInterface public interface TaskDecorator

A callback interface for a decorator to be applied to any Runnable about to be executed.

Note that such a decorator is not necessarily being applied to the user-supplied Runnable/Callable but rather to the actual execution callback (which may be a wrapper around the user-supplied task).

The primary use case is to set some execution context around the task's invocation, or to provide some monitoring/statistics for task execution.

Since:4.3

 

์ž, ๊ทธ๋Ÿผ TaskDecorator๋ฅผ ๊ตฌํ˜„ํ•œ ์ด LoggingTaskDecorator๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ๊นŒ?

๊ฐ„๋‹จํ•˜๋‹ค. ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” ThreadPoolTaskExecutor๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด setTaskDecorator() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์„ธํŒ…ํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();
        t.setTaskDecorator(new LoggingTaskDecorator());
        return t;
}

 

 

async(๋น„๋™๊ธฐ) ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ThreadPoolTaskExecutor

ThreadPoolTaskExecutor๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ThreadPoolTaskExecutor๋Š” ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ํด๋ž˜์Šค๋กœ org.springframework.scheduling.concurrent ํŒจํ‚ค์ง€์— ์†ํ•ด์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž๋„ ๊ธฐ๋ณธ์ƒ์„ฑ์ž ํ•˜๋‚˜๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์“ฐ๋ ˆ๋“œํ’€์„ ์ด์šฉํ•˜์—ฌ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ๊ตฌํ˜„์„ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

	public static void main(String[] args) {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.initialize();
	}

ThreadPoolTaskExecutor ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก initialize()๋ฅผ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒ๋ฉด ์ด๋‹ˆ์…œ๋ผ์ด์ฆˆํ•˜๊ธฐ ์ „์—๋Š” executor๋ฅผ ์‚ฌ์šฉ์„ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด๋‹ˆ์…œ๋ผ์ด์ฆˆ ํ•˜๊ธฐ ์ „์— ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

Exception in thread "main" java.lang.IllegalStateException: ThreadPoolTaskExecutor not initialized

 

๊ทธ๋Ÿผ ์ด์ œ ์•„๋ž˜์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ข€ ๋” ์ถ”๊ฐ€ํ•œ ๋’ค ์‹ค์ œ๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

	public static void main(String[] args) {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.initialize();
		
		log.info("executing threads....");
		Runnable r = () -> {
			try {
				log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		};

		for (int i = 0; i < 10; i++) {
			executor.execute(r);
		}
	}

 

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ•œ๋ฒˆ ๋ณผ๊นŒ์š”?

07:42:09.450 [main] INFO com.keichee.test.service.TestService - executing threads....
07:42:09.460 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:42:19.464 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:42:29.465 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:42:39.470 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:42:49.472 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:42:59.477 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:43:09.483 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:43:19.489 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:43:29.491 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
07:43:39.496 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...

๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋œ ์‹œ๊ฐ„์„ ๋ณด๋ฉด 10์ดˆ๋งˆ๋‹ค ์ถœ๋ ฅ์ด ๋˜๊ณ ์žˆ๊ณ  ์“ฐ๋ ˆ๋“œ๋„ ThreadPoolTaskExecutor-1 ํ•˜๋‚˜๊ฐ€ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ง€๊ธˆ ์œ„ ์ฝ”๋“œ๋Š” ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋กœ ๋Œ์•„๊ฐ„๊ฒŒ ์•„๋‹ˆ๋ž€ ์–˜๊ธฐ์ฃ . ThreadPoolTaskExecutor๋Š” ๋ช‡ ๊ฐ€์ง€ ์„ค์ •๊ฐ’๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ corePoolSize ๊ฐ’์ด ๋™์‹œ์— ์‹คํ–‰ํ•  ์“ฐ๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๋Š”๋ฐ ์ด ์„ค์ •์˜ default ๊ฐ’์ด 1๋กœ ์„ธํŒ…๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„ ์ฒ˜๋Ÿผ corePoolSize ์„ค์ •์—†์ด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์‹ฑ๊ธ€์“ฐ๋ ˆ๋“œ๋กœ ๋Œ์•„๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

์„ค์ •๊ฐ’

๊ทธ๋Ÿผ ์„ค์ •๊ฐ’๋“ค์— ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€ ๊ทธ๊ฒƒ๋“ค์ด ์˜๋ฏธํ•˜๋Š”๊ฒŒ ๋ฌด์—‡์ธ์ง€ setter ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ค‘์š”ํ•œ ๊ฐ’๋“ค๋งŒ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฉ”์„œ๋“œ

์„ค๋ช…

๊ธฐ๋ณธ๊ฐ’

setCorePoolSize

corePoolSize ๊ฐ’์„ ์„ค์ •ํ•จ. corePoolSize๋Š” ๋™์‹œ์— ์‹คํ–‰์‹œํ‚ฌ ์“ฐ๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•จ

1

setAllowCoreThreadTimeOut

์ฝ”์–ด ์“ฐ๋ ˆ๋“œ์˜ ํƒ€์ž„์•„์›ƒ์„ ํ—ˆ์šฉํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์„ธํ„ฐ ๋ฉ”์„œ๋“œ. true๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ ์ฝ”์–ด ์“ฐ๋ ˆ๋“œ๋ฅผ 10์œผ๋กœ ์„ค์ •ํ–ˆ์–ด๋„ ์ผ์ • ์‹œ๊ฐ„(keepAliveSeconds)์ด ์ง€๋‚˜๋ฉด ์ฝ”์–ด ์“ฐ๋ ˆ๋“œ ๊ฐœ์ˆ˜๊ฐ€ ์ค„์–ด๋“ฆ.

false

setKeepAliveSeconds

์ฝ”์–ด ์“ฐ๋ ˆ๋“œ ํƒ€์ž„์•„์›ƒ์„ ํ—ˆ์šฉํ–ˆ์„ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋˜๋Š” ์„ค์ •๊ฐ’์œผ๋กœ, ์—ฌ๊ธฐ ์„ค์ •๋œ ์‹œ๊ฐ„์ด ์ง€๋‚  ๋•Œ๊นŒ์ง€ ์ฝ”์–ด ์“ฐ๋ ˆ๋“œ ํ’€์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋Š” terminate ๋œ๋‹ค.

60์ดˆ

setMaxPoolSize

์“ฐ๋ ˆ๋“œ ํ’€์˜ ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ

Integer.MAX

setQueueCapacity

์“ฐ๋ ˆ๋“œ ํ’€ ํ์˜ ์‚ฌ์ด์ฆˆ. corePoolSize ๊ฐœ์ˆ˜๋ฅผ ๋„˜์–ด์„œ๋Š” task๊ฐ€ ๋“ค์–ด์™”์„ ๋•Œ queue์— ํ•ด๋‹น task๋“ค์ด ์Œ“์ด๊ฒŒ ๋œ๋‹ค. ์ตœ๋Œ€๋กœ maxPoolSize ๊ฐœ์ˆ˜ ๋งŒํผ ์Œ“์ผ ์ˆ˜ ์žˆ๋‹ค.

Integer.MAX

 

์—ฌ๊ธฐ์„œ corePoolSize, maxPoolSize, queueCapacity ์ด ์„ธ ๊ฐ€์ง€ ์„ค์ •๊ฐ’์ด ๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„  ์œ„์—์„œ ๋ดค๋˜ ์ฒซ ๋ฒˆ์งธ ์˜ˆ์ œ์—์„œ๋Š” ์ด ์„ธ ๊ฐ€์ง€ ๊ฐ’์— ๋Œ€ํ•ด์„œ ๋ณ„๋„๋กœ ์„ค์ •์„ ํ•˜์ง€ ์•Š์•˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ๋กœ ์ž‘์—…์ด ์ด๋ฃจ์–ด์กŒ์ฃ .

 

corePoolSize

์ด๋ฒˆ์—๋Š” corePoolSize๋ฅผ ์˜ฌ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.initialize();

        log.info("executing threads....");
        Runnable r = () -> {
            try {
                log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        for (int i = 0; i < 10; i++) {
            executor.execute(r);
        }
    }

 

corePoolSize๋ฅผ 5๋กœ ์„ค์ • ํ›„ ์‹คํ–‰ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. (queueCapacity์™€ maxPoolSize๊ฐ’์€ ํ˜„์žฌ ๊ธฐ๋ณธ๊ฐ’์ธ Integer.MAX ์ž…๋‹ˆ๋‹ค)

08:52:50.423 [main] INFO com.keichee.test.service.TestService - executing threads....
08:52:50.456 [ThreadPoolTaskExecutor-3] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-3, Now sleeping 10 seconds...
08:52:50.456 [ThreadPoolTaskExecutor-2] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-2, Now sleeping 10 seconds...
08:52:50.456 [ThreadPoolTaskExecutor-5] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-5, Now sleeping 10 seconds...
08:52:50.456 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
08:52:50.456 [ThreadPoolTaskExecutor-4] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-4, Now sleeping 10 seconds...
08:53:00.460 [ThreadPoolTaskExecutor-1] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-1, Now sleeping 10 seconds...
08:53:00.460 [ThreadPoolTaskExecutor-2] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-2, Now sleeping 10 seconds...
08:53:00.461 [ThreadPoolTaskExecutor-3] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-3, Now sleeping 10 seconds...
08:53:00.461 [ThreadPoolTaskExecutor-4] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-4, Now sleeping 10 seconds...
08:53:00.461 [ThreadPoolTaskExecutor-5] INFO com.keichee.test.service.TestService - ThreadPoolTaskExecutor-5, Now sleeping 10 seconds...

์‹คํ–‰๋˜์ž๋งˆ์ž 5๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ  10์ดˆ ํ›„์— ๋˜ ๋‹ค๋ฅธ 5๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, queueCapacity์™€ maxPoolSize๊ฐ’์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•ด๋†“์œผ๋ฉด corePoolSize์˜ ๊ฐ’๋งŒํผ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

corePoolSize์™€ queueCapacity

๊ทธ๋Ÿผ ์ด๋ฒˆ์—๋Š” corePoolSize๋Š” default ๊ฐ’์ธ 1๋กœ ๋†”๋‘๊ณ  queueCapacity์™€ maxPoolSize ๊ฐ’์„ 5๋กœ ์„ค์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  10๊ฐœ์˜ task๊ฐ€ ์‹คํ–‰๋  ๋•Œ poolSize, activeSize, queueSize ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ถœ๋ ฅํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜, ์ถœ๋ ฅ์„ ์ข€ ์งง๊ฒŒ ํ•˜๊ธฐ์œ„ํ•ด์„œ ์“ฐ๋ ˆ๋“œ๋ช… prefix๋ฅผ "my-"๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("my-");
        executor.setQueueCapacity(5);
        executor.setMaxPoolSize(5);
        executor.initialize();

        log.info("executing threads....");
        Runnable r = () -> {
            try {
                log.info(Thread.currentThread().getName() + ", Now sleeping 10 seconds...");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        for (int i = 0; i < 10; i++) {
            executor.execute(r);
            System.out.print("poolSize:" + executor.getPoolSize());
            System.out.print(", active:" + executor.getActiveCount());
            System.out.println(", queue:" + executor.getThreadPoolExecutor().getQueue().size());
        }
    }

 

์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ๊ฒƒ ๊ฐ™์€์ง€ ํ•œ๋ฒˆ ์ƒ๊ฐ์„ ํ•ด๋ณด๊ณ  ์•„๋ž˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

09:02:22.864 [main] INFO com.keichee.test.service.TestService - executing threads....
poolSize:1, active:1, queue:0
poolSize:1, active:1, queue:1
poolSize:1, active:1, queue:2
poolSize:1, active:1, queue:3
poolSize:1, active:1, queue:4
poolSize:1, active:1, queue:5
poolSize:2, active:2, queue:5
09:02:22.886 [my-1] INFO com.keichee.test.service.TestService - my-1, Now sleeping 10 seconds...
09:02:22.887 [my-2] INFO com.keichee.test.service.TestService - my-2, Now sleeping 10 seconds...
poolSize:3, active:3, queue:5
09:02:22.887 [my-3] INFO com.keichee.test.service.TestService - my-3, Now sleeping 10 seconds...
poolSize:4, active:4, queue:5
09:02:22.887 [my-4] INFO com.keichee.test.service.TestService - my-4, Now sleeping 10 seconds...
poolSize:5, active:5, queue:5
09:02:22.887 [my-5] INFO com.keichee.test.service.TestService - my-5, Now sleeping 10 seconds...
09:02:32.888 [my-1] INFO com.keichee.test.service.TestService - my-1, Now sleeping 10 seconds...
09:02:32.890 [my-2] INFO com.keichee.test.service.TestService - my-2, Now sleeping 10 seconds...
09:02:32.890 [my-4] INFO com.keichee.test.service.TestService - my-4, Now sleeping 10 seconds...
09:02:32.890 [my-5] INFO com.keichee.test.service.TestService - my-5, Now sleeping 10 seconds...
09:02:32.890 [my-3] INFO com.keichee.test.service.TestService - my-3, Now sleeping 10 seconds...

 

 

์œ„ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด 10๊ฐœ์˜ task๋ฅผ ์‹คํ–‰ํ•  ๋•Œ queue ์‚ฌ์ด์ฆˆ๊ฐ€ 0์—์„œ 5๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€๊ณ  ๊ทธ ์ดํ›„์— poolSize์™€ active ์‚ฌ์ด์ฆˆ๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. corePoolSize๊ฐ€ 1 ์ด๋ผ์„œ 2๋ฒˆ์งธ task๋ถ€ํ„ฐ 6๋ฒˆ์งธ task๊นŒ์ง€๋Š” queue์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  7๋ฒˆ์งธ task๋ถ€ํ„ฐ 10๋ฒˆ์งธ task๊นŒ์ง€ 4๊ฐœ์˜ task๋Š” maxPoolSize ๋ฅผ ๋„˜์–ด์„œ์ง€ ์•Š๋Š” ํ•œ ์ถ”๊ฐ€๋กœ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ pool์— ๋„ฃ๊ณ  ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋กœ ๊ฐ task๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

๊ทธ๋Ÿผ ๋งŒ์•ฝ maxPoolSize๋ฅผ ๋„˜์–ด์„ค ๋งŒํผ ๋งŽ์€ ์–‘์˜ task๋“ค์ด ๋“ค์–ด์˜จ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

Exception in thread "main" org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@32eff876[Running, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]] did not accept task: com.keichee.test.service.TestService$$Lambda$22/0x00000008000ce840@5e0826e7
	at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:324)

TaskRejectedException ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

๋”ฐ๋ผ์„œ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์–‘์˜ task๋ฅผ ์†Œํ™”ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์ •ํ™•ํžˆ ์•Œ๊ณ  corePoolSize, queueCapacity, maxPoolSize์— ์ ์ ˆํ•œ ๊ฐ’์„ ์„ธํŒ…ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด TaskRejectedException์„ ๋ณผ ์ผ์€ ๊ฑฐ์˜ ์—†๊ฒ ์ง€๋งŒ ๊ทธ ๋Œ€์‹  queue์— ์–ด๋งˆ์–ด๋งˆํ•œ ์–‘์˜ task๊ฐ€ ์Œ“์ด๊ฒ ์ฃ . ๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฐฐํฌ๋‚˜ ์–ด๋–ค ์ด์œ ์— ์˜ํ•ด์„œ ์žฌ๊ธฐ๋™์ด ํ•„์š”ํ•˜๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น queue์— ์Œ“์—ฌ์žˆ๋˜ task๋“ค์€ ์‚ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ ์‚ฌ์šฉํ•˜์‹ค ๋ถ„๋“ค์€ ์•„๋ž˜ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ThreadPoolTaskExecutor๋ฅผ ์„ค์ • ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

 

Converting timestamp to date time string format and vice versa

 

์‹ค์ œ ์—…๋ฌด์—์„œ java๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ•  ๋•Œ ๋‚ ์งœ/์‹œ๊ฐ„์„ ๋‹ค๋ค„์•ผ ํ•  ๋•Œ๊ฐ€ ์ฐธ ๋งŽ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ์‹œ๊ฐ„์„ ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜ ๋กœ๊น…์„ ํ•˜๊ฑฐ๋‚˜ ๋“ฑ๋“ฑ ๋ง์ด์ฃ .

๊ทธ๋ž˜์„œ ์˜ค๋Š˜์€ ์‹œ๊ฐ„ ๋ณ€ํ™˜์— ๋Œ€ํ•ด์„œ ์งง๊ฒŒ ํ•œ๊ฐ€์ง€๋งŒ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ž๋ฐ” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‹œ์ž‘ํ•œ์ง€ ์–ผ๋งˆ ์•ˆ๋˜์—ˆ์„ ๋•Œ System.currentTimemillis()๋ฅผ ์ด์šฉํ•ด์„œ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ๋Œ์•„๊ฐ€๋Š”์ง€ ํ™•์ธ์„ ํ–ˆ์—ˆ๋Š”๋ฐ์š”, ์ € ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋Š” longํ˜•์ž…๋‹ˆ๋‹ค. 

1970๋…„ 1์›” 1์ผ UTC ์ž์ • ์ดํ›„๋กœ ๋ช‡ ๋ฐ€๋ฆฌ์ดˆ๊ฐ€ ์ง€๋‚ฌ๋Š”์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ์ฃ .

๋ฐ˜ํ™˜๊ฐ’์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ์ •์˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

   * @return  the difference, measured in milliseconds, between
   *          the current time and midnight, January 1, 1970 UTC.

 

๊ทธ๋Ÿฐ๋ฐ ์ด longํ˜• ์ˆซ์ž๋Š” ๊ธธ์ด๋„ ๊ธธ๊ณ  ์ด๊ฒŒ ๋„๋Œ€์ฒด ๊ทธ๋ž˜์„œ ๋ช‡ ์ผ ๋ช‡ ์‹œ ๋ผ๋Š” ๊ฑด์ง€๋ฅผ ์•Œ์•„๋ณด๊ธฐ๊ฐ€ ํž˜๋“ค์ฃ 

๊ทธ๋ž˜์„œ ์ด longํ˜• ์ˆซ์ž๋ฅผ ๊ฐ€๋…์„ฑ์žˆ๊ฒŒ ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‹œ๊ฐ„ ํฌ๋งท์— ๋งž๊ฒŒ String ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋ ‡๊ฒŒ ์–ป์€ String ํƒ€์ž… ์‹œ๊ฐ„๊ฐ’์„ ๋‹ค์‹œ longํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด ๋˜ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

 

์šฐ์„  longํƒ€์ž… ์‹œ๊ฐ„์„ ์›ํ•˜๋Š” ์ผ์‹œ ํฌ๋งท์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ Date์™€ SimpleDateFormat์„ ์ด์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋ง์ด์ฃ .

 public static void main(String[] args) {
     Date d = new Date(vv);
     DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
     String bb = format.format(d);
     System.out.println(bb);
 }

 

๋ฐ˜๋Œ€๋กœ String์œผ๋กœ ๋œ ์ผ์‹œ๋ฅผ long์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด java.sql.Timestamp๋ฅผ ์ด์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

public static void main(String[] args) {
    String prdt = "2020-01-10 10:38:09.419";
    long vv = Timestamp.valueOf(prdt).getTime();
    System.out.println(vv);
}

 

ํ•˜์ง€๋งŒ Timestamp.valueOf(String) ๋ฉ”์„œ๋“œ๋Š” "yyyy-mm-dd hh:mm:ss[.fffffffff]" ํ˜•ํƒœ์˜ string๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ผ์ž๋งŒ ์žˆ๊ฑฐ๋‚˜ ์‹œ๊ฐ„๊ฐ’๋งŒ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋‹ค๋Š” ๊ฒƒ ๋ช…์‹ฌํ•˜์„ธ์š”.

๋งŒ์•ฝ ์ผ์‹œ ํฌ๋งท์„ ์ž˜๋ชป ์ž…๋ ฅํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Exception in thread "main" java.lang.IllegalArgumentException: 
		Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]

 

java.sql.Timestamp ๋Œ€์‹ ์— LocalDateTime์„ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

public static void main(String[] args) {

    String prdt2 = "2020-01-11 00:00:00";
    System.out.println(Timestamp.valueOf(prdt2).getTime());
    System.out.println(LocalDateTime.parse("2020-01-11T00:00:00")
        .atZone(ZoneId.of("Asia/Seoul"))
        .toInstant()
        .toEpochMilli());
}

---์ถœ๋ ฅ๊ฒฐ๊ณผ---
1578668400000
1578668400000

 

ํ•˜์ง€๋งŒ LocalDateTime์˜ ๊ฒฝ์šฐ parseํ•  ๋•Œ ๋“ค์–ด๊ฐ€๋Š” stringํ˜•ํƒœ์˜ ์ผ์‹œ๊ฐ’์— 'T'๊ตฌ๋ถ„์ž๋ฅผ ํฌํ•จํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ์‹ฑ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Exception in thread "main" java.time.format.DateTimeParseException: 
		Text '2020-01-11 00:00:00' could not be parsed at index 10

 

 

Summary

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ž๋ฐ”์—์„œ longํƒ€์ž…์˜ timestampe๋ฅผ String ํƒ€์ž…์˜ ๊ฐ€๋…์„ฑ ์ข‹์€ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ž‘์—…๊ณผ ๊ทธ๋ ‡๊ฒŒ ๋ณ€ํ™˜๋œ String์„ ๋‹ค์‹œ long์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

long -> String -> long ๋ณ€๊ฒฝ์„ ํ–ˆ์„ ๋•Œ ๋™์ผํ•œ ๊ฐ’์ด ๋‚˜์˜ค๋Š”์ง€๋„ ์•„๋ž˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

public static void main(String[] args) {

    // String to long conversion 1
    String prdt = "2020-01-11 10:24:09.419";
    long l1 = Timestamp.valueOf(prdt).getTime();
    System.out.println(l1);

    // String to long conversion 2
    String prdt2 = "2020-01-11T10:24:09.419";
    long l2 = LocalDateTime.parse(prdt2)
        .atZone(ZoneId.of("Asia/Seoul"))
        .toInstant()
        .toEpochMilli();
    System.out.println(l2);

    // long to String conversion
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    System.out.println(format.format(new Date(l1)));
}

---์ถœ๋ ฅ๊ฒฐ๊ณผ---
1578705849419
1578705849419 <-- Timestamp๋ฅผ ์ด์šฉํ•ด์„œ ์–ป์€ ๊ฒฐ๊ณผ์™€ ๋™์ผํ•จ์„ ํ™•์ธ 
2020-01-11 10:24:09.419 <-- long์œผ๋กœ ๋ณ€ํ™˜ํ–ˆ๋˜ String ํ˜•ํƒœ์˜ ์‹œ๊ฐ„๊ณผ ๋™์ผํ•˜๊ฒŒ ์ถœ๋ ฅ๋˜๋Š”์ง€ ํ™•์ธ

 

์ด์ƒ์œผ๋กœ Java์—์„œ datetime์„ long์—์„œ String์œผ๋กœ ๋‹ค์‹œ String์—์„œ long์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

์œ ์šฉํ–ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๊พน ๋ถ€ํƒํ•ด์š”~

 

์ž๋ฐ”์—์„œ 8์ง„์ˆ˜ ์ˆซ์ž๋ฅผ ์‚ฌ์šฉ์ž(ํ‚ค๋ณด๋“œ)๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๋ฐ›์•„์„œ 10์ง„์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.


import java.util.Scanner;

public class OctalToDex
{
  public static void main(String[] args)
  {
    Scanner sc = new Scanner(System.in);
    String b=sc.nextLine();
    int a=Integer.valueOf(b, 8);
    sc.close();
    System.out.println(a);
   }
} 


Java์—์„œ๋Š” Integerํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•˜์—ฌ 2์ง„์ˆ˜, 8์ง„์ˆ˜, 16์ง„์ˆ˜์˜ ์ˆซ์ž๋ฅผ 10์ง„์ˆ˜๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ทธ ๋ฐ˜๋Œ€๋กœ 10์ง„์ˆ˜๋ฅผ 2์ง„์ˆ˜,8์ง„์ˆ˜,16์ง„์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ์‰ฝ๊ฒŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
 10์ง„์ˆ˜ -> 2์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toBinaryString(int);
 10์ง„์ˆ˜ -> 8์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toOctalString(int);
10์ง„์ˆ˜ -> 16์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toHexString(int);
 10์ง„์ˆ˜ -> 2์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toBinaryString(int); 
 10์ง„์ˆ˜ -> 8์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toOctalString(int);
 10์ง„์ˆ˜ -> 16์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.toHexString(int);โ€‹


์œ„ ๋ฉ”์„œ๋“œ๋Š” 10์ง„์ˆ˜ ์ˆซ์ž(int)๋ฅผ 2์ง„์ˆ˜/8์ง„์ˆ˜/16์ง„์ˆ˜ ์ŠคํŠธ๋ง์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 2์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 2);
 8์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 8);
16์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 10);
2์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 2);
8์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 8);
16์ง„์ˆ˜ -> 10์ง„์ˆ˜ ๋ณ€ํ™˜ : Integer.valueOf(string, 10);โ€‹


์œ„ ๋ฉ”์„œ๋“œ๋Š” 2์ง„์ˆ˜/8์ง„์ˆ˜/16์ง„์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ˆซ์ž์ŠคํŠธ๋ง์„ 10์ง„์ˆ˜ int๋กœ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.
์„ธ๋กœ๋กœ ๋‚˜์—ด๋œ 5๊ฐœ์˜ ๋„ค์Šคํ”„๋ ˆ์†Œ ๋ฐฐ์—ด

์ด๋ฒˆ์—๋Š” ์ž๋ฐ”๋กœ 1์ฐจ์› ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
์ž๋ฐ”๋กœ ๋ฐฐ์—ด์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ์„  ์šฉ์–ด๋ถ€ํ„ฐ ์ •๋ฆฌํ•˜๊ณ  ๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.
์ œ๊ฐ€ ๋งŒ๋“ ๋‹ค๋ผ๊ณ  ์–˜๊ธฐํ•œ ๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์–˜๊ธฐํ•˜๋ ค๊ณ  ํ•œ ๊ฒƒ์ธ๋ฐ ์ด๋Š” ๋‘ ๊ฐ€์ง€ ์˜๋ฏธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ”๋กœ "์„ ์–ธ"๊ณผ "์ดˆ๊ธฐํ™”"์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์„œ "์„ ์–ธ"์ด๋ผ๋Š” ๊ฒƒ์€ ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ ์ง€์–ด์ฃผ๋Š” ๊ฒƒ์„ ์–˜๊ธฐํ•˜๋ฉฐ,
"์ดˆ๊ธฐํ™”"๋ผ๋Š” ๊ฒƒ์€ ๊ทธ ๋ณ€์ˆ˜์— ๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
์ด ์šฉ์–ด๋“ค์„ ๋จธ๋ฆฟ์†์— ๋„ฃ๊ณ  ์ถœ๋ฐœํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•

์ž๋ฐ”์—์„œ ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์ด 3๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

public static void main(String[] args) {

        // ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•
        int[] intArr1;
        int []intArr2;
        int intArr3[];
}

์œ„์—์„œ๋Š” int ํƒ€์ž…์˜ ๋ฐฐ์—ด์„ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์„ ์–ธํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
intํƒ€์ž… ๋Œ€์‹  long, double, Integer, Long, Double, String ๋“ฑ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ์„ ์–ธ์„ ํ•ด ๋†“์•„๋„ ๊ณต๊ฐ„(๋ฉ”๋ชจ๋ฆฌ)์„ ์ฐจ์ง€ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
๋ฐฐ์—ด์€ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋ฉด์„œ ์‚ฌ์ด์ฆˆ๋ฅผ ์ •ํ•ด์ค˜์•ผ ๊ณต๊ฐ„(๋ฉ”๋ชจ๋ฆฌ)์„ ์ฐจ์ง€ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿผ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”๋Š” ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•

๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค.

public static void main(String[] args) {

        // ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•
        int[] intArr1;

        // ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•
        intArr1 = new int[3];
}

์œ„ ์˜ˆ์ œ์—์„œ๋Š” intArr1์ด๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ฐฐ์—ด์„ ์‚ฌ์ด์ฆˆ๊ฐ€ 3์ธ ๋ฐฐ์—ด๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋ฉด int ํƒ€์ž…์˜ ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ 0์œผ๋กœ ์„ธํŒ…์ด ๋ฉ๋‹ˆ๋‹ค.

๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•˜๋Š” ๋ฐฉ๋ฒ•

์ž๋ฐ”์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

public static void main(String[] args) {

        int[] intArr1 = new int[10];    // size 10, index range from 0 to 9
        int []intArr2 = new int[20];    // size 20, index range from 0 to 19
        int intArr3[] = new int[20];    // size 20, index range from 0 to 19
}

์œ„์—์„œ ์„ค๋ช…๋“œ๋ฆฐ ์„ ์–ธ๋ฌธ๊ณผ ์ดˆ๊ธฐํ™”๋ฌธ์„ ํ•œ ์ค„์— ๋ถ™์—ฌ ์“ฐ๋ฉด ๋™์‹œ์— ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ž, ๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด int ํƒ€์ž…์˜ ๋ฐฐ์—ด์—๋Š” ๋ชจ๋‘ 0์œผ๋กœ ๊ฐ’์ด ์„ธํŒ…์ด ๋ฉ๋‹ˆ๋‹ค.

์ „, ์ œ๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์„ธํŒ…์„ ํ•˜๊ณ  ์‹ถ์€๋ฐ ๊ทธ๋ ‡๊ฒŒ๋„ ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

๋ฌผ๋ก ์ด์ฃ ~ ๊ทธ๋ ‡๊ฒŒ๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

public static void main(String[] args) {

        int[] intArr4 = {1, 2, 3, 4};   // size 4, index range from 0 to 3
        int[] intArr5 = {0, 0, 0, 0, 0, 0, 0};  // size 7, index range from 0 to 6
}

intArr4์—๋Š” [1, 2, 3, 4]๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
intArr5์—๋Š” new int[7] ๋กœ ์ดˆ๊ธฐํ™”ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด 0์œผ๋กœ ๊ฐ’์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.

๋ฐฐ์—ด ์ถœ๋ ฅํ•˜๊ธฐ

๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ๋ฐฐ์—ด์— ๋“ค์–ด๊ฐ„ ๊ฐ’์„ ์ถœ๋ ฅํ•ด๋ณด๊ณ  ์‹ถ์„ ๋• ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?
์ž๋ฐ”์—์„œ ์ฝ˜์†”์ฐฝ์— ์ถœ๋ ฅ์„ ํ•  ๋•Œ์—๋Š” System.out.println() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋‹ค๋“ค ์•Œ๊ณ  ๊ณ„์‹œ์ฃ ?
Hello World๋ฅผ ํ•ด๋ณด์…จ๋‹ค๋ฉด ๋‹ค๋“ค ์•Œ๊ณ  ๊ณ„์‹ค๊ฒ๋‹ˆ๋‹ค.
๊ทธ๋Ÿผ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ๋ณ€์ˆ˜์ด๋ฆ„์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋ ๊นŒ์š”?
์•„๋‹™๋‹ˆ๋‹ค. ๋ฐฐ์—ด์ด ๋‹ด๊ธด ๋ณ€์ˆ˜๋ช…๋งŒ ๋„ฃ์–ด์ฃผ๋ฉด ์“ฐ๋ ˆ๊ธฐ๊ฐ’์ด ์ถœ๋ ฅ์ด ๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” Arrays.toString() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

public static void main(String[] args) {

        int[] intArr1 = new int[10];    // size 10, index range from 0 to 9
        int []intArr2 = new int[20];    // size 20, index range from 0 to 19
        int intArr3[] = new int[20];    // size 20, index range from 0 to 19
        int[] intArr4 = {1, 2, 3, 4};   // size 4, index range from 0 to 3
        int[] intArr5 = {0, 0, 0, 0, 0, 0, 0};  // size 7, index range from 0 to 6

        System.out.println(Arrays.toString(intArr1));
        System.out.println(Arrays.toString(intArr2));
        System.out.println(Arrays.toString(intArr3));
        System.out.println(Arrays.toString(intArr4));
        System.out.println(Arrays.toString(intArr5));
}

์ถœ๋ ฅ ๊ฒฐ๊ณผ

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 2, 3, 4]
[0, 0, 0, 0, 0, 0, 0]

์ด์ƒ์œผ๋กœ ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์„ ๋งˆ์น˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ์‹œ๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ๋‹ต๋ณ€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

2์ฐจ์› ๋ฐฐ์—ด์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ [Java] ์ž๋ฐ” 2์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ(์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”)์—์„œ ๋” ๋‹ค๋ฃจ๊ณ  ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๊ตฌ์š”~

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด ๊ณต๊ฐ ๊พธ~~~~์šฑ ๋ˆŒ๋Ÿฌ์ฃผ๊ณ  ๊ฐ€์„ธ์š” ^-^

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ง€๋‚œ ์‹œ๊ฐ„์—๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ์ง€๋ฃจํ•œ ์ด๋ก ์ ์ธ ์ด์•ผ๊ธฐ ๋ณด๋‹ค๋Š” ๊ฐœ๋ฐœ์ž๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ ๋Š๋‚Œ์ ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ •์˜๋ฅผ ๋‚ด๋ ธ์—ˆ๋Š”๋ฐ

์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฆฌ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 

 

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” ๋ฌด์ž‘์ • ๋”ฐ๋ผํ•˜๊ธฐ ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์šฐ์„  ์—ฌ๋Ÿฌ๋ถ„๋“ค ์ปดํ“จํ„ฐ์— ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์„ ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

1. JDK (Java Development Kit)

2. ์ดํด๋ฆฝ์Šค IDE (Integrated Development Environment)

 

์„ค์น˜ํ•˜๊ธฐ ์ „์— ์ด์นœ๊ตฌ๋“ค์ด ๋ญ”์ง€๋ถ€ํ„ฐ ์•Œ๊ณ  ์„ค์น˜๋ฅผ ํ•ด์•ผ๊ฒ ์ฃ ? ํ•ดํ‚นํ”„๋กœ๊ทธ๋žจ์ด๋ฉด ํฐ ์ผ ๋‚  ํ…Œ๋‹ˆ๊นŒ์š”.

์šฐ์„ , JDK๋ผ๋Š” ์นœ๊ตฌ๋Š” "์ž๋ฐ” ๊ฐœ๋ฐœ ํˆด" ์ค„์—ฌ์„œ "์ž๊ฐœํˆด"์ด๋ผ๋Š” ๋…€์„์ด์ฃ . ์ž๋ฐ” ์–ธ์–ด ์‚ฌ์ „์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ๋…€์„์ด ์žˆ์–ด์•ผ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์ž‘์„ฑํ•œ ์ž๋ฐ”์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ปดํ“จํ„ฐ๊ฐ€ ์ดํ•ดํ•˜๋Š” ์–ธ์–ด๋กœ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๊ณ ,

์ž๋ฐ” ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒœ์ƒ๋ถ€ํ„ฐ ํ˜„์žฌ๊นŒ์ง€ ๋ฌด๋ฃŒ์ž…๋‹ˆ๋‹ค. (Java 8์˜ ํŠน์ • ๋ฒ„์ „ ๋ถ€ํ„ฐ๋Š” ์œ ๋ฃŒ๋ผ์ด์„ผ์Šค๋กœ ์ „ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค)

 

๋‹ค์Œ์œผ๋กœ ์ดํด๋ฆฝ์Šค๋ผ๋Š” ์นœ๊ตฌ๋Š” ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ๊ฐœ๋ฐœ์„ ์ข€ ๋” ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ์œ„ํ•ด

์˜คํ”ˆ์†Œ์Šค๋กœ ๊ณต๊ฐœ๋œ ๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ "ํ†ตํ•ฉ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ"์„ ์ œ๊ณตํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ์†Œ์„ค์ž‘๊ฐ€๋ผ๋ฉด ์ดํด๋ฆฝ์Šค IDE๋Š” ์›Œ๋“œํ”„๋กœ์„ธ์„œ์™€ ๊ฐ™์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

 

์ž, ๊ทธ๋Ÿผ ์„ค์น˜๋ฅผ ํ•˜๋Ÿฌ ๊ฐ€๋ณผ๊นŒ์š”??

 

1. JDK 8 (Java SE Development Kit 8) ์„ค์น˜ -> ๋‹ค์šด๋กœ๋“œ ๋งํฌ

-> ํ˜น์‹œ ๋‹ค์šด๋กœ๋“œ ๋งํฌ ๋“ค์–ด๊ฐ”๋Š”๋ฐ cookie ๊ด€๋ จ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฐฝ์ด ๋œฌ๋‹ค๋ฉด ๊ทธ๋ƒฅ I agree ํ•˜์ง€๋งˆ์‹œ๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ๋”ฐ๋ผํ•ด์ฃผ์„ธ์š”.

1. ์ฃผํ™ฉ์ƒ‰ ๋ฒ„ํŠผ ํด๋ฆญ
2. Required Cookies ๋งŒ ์„ ํƒ๋˜๋„๋ก ํ•œ๋’ค Submit Preferences  ์„ ํƒ
3. Close ๋ฒ„ํŠผ ์„ ํƒ
4. Accept License Agreement ์„ ํƒ ํ›„ ๋ณธ์ธ ์šด์˜์ฒด์ œ์— ๋งž๋Š” ๋ฒ„์ „์„ ๋‹ค์šด๋กœ๋“œ

2. ์ดํด๋ฆฝ์Šค(๊ฐœ๋ฐœํˆด, IDE) ์„ค์น˜ -> ๋‹ค์šด๋กœ๋“œ ๋งํฌ

 

1. Download ์„ ํƒ

 

3. ์ด์ œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ JDK ์„ค์น˜ ํŒŒ์ผ์„ "๋”๋ธ”ํด๋ฆญ"ํ•ด์„œ ์„ค์น˜ํ•ด์ฃผ์„ธ์š”.

-> ์„ค์น˜ ์‹œ ์„ธํŒ…(์„ค์น˜ ๊ฒฝ๋กœ ๋ณ€๊ฒฝ ๋“ฑ)์€ ํ•˜์ง€๋ง๊ณ  ๊ธฐ๋ณธ๊ฐ’ ๊ทธ๋Œ€๋กœ Next, Next ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์œˆ๋„์šฐ์—์„œ๋Š” cmd์ฐฝ, Mac์—์„œ๋Š” ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž๋ฐ”์˜ ๋ฒ„์ „์„ ํ™•์ธํ•˜๋Š” ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด๋ณด์„ธ์š”.

java -version

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ๋‚˜์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋ฒ„์ „์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ˆซ์ž๋Š” ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ” ๋ฒ„์ „ ํ™•์ธ

์—ฌ๊ธฐ์„œ ํ™•์ธํ•  ๊ฒƒ์€ ์„ธ ๋ฒˆ ์งธ ์ค„์— HotSpot์ด๋ผ๊ณ  ๋œจ๋Š”์ง€๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

(์ž๋ฐ”๋Š” ์‹คํ–‰ํ™˜๊ฒฝ๋งŒ ์ œ๊ณตํ•˜๋Š” JRE์™€ ๊ฐœ๋ฐœํ™˜๊ฒฝ๊นŒ์ง€ ์ œ๊ณตํ•˜๋Š” JDK๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ €ํฌ๋Š” JDK๋ฅผ ์„ค์น˜ํ•œ ๊ฒƒ์ด๊ณ  JDK์˜ ๋ฒ„์ „์—๋Š” ์ €๋ ‡๊ฒŒ HotSpot Server VM์ด๋ผ๋Š” ๊ฒŒ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.)

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ์˜ค์…จ๋‹ค๋ฉด ์ด์ œ ์ดํด๋ฆฝ์Šค๋ฅผ ์„ค์น˜ํ•ด์ฃผ์„ธ์š”.

์ดํด๋ฆฝ์Šค ์„ค์น˜ ํ™”๋ฉด

์šฐ๋ฆฌ๋Š” ์ดํด๋ฆฝ์Šค ์ธ์Šคํ†จ๋Ÿฌ์—์„œ ์œ„์—์„œ ๋‘ ๋ฒˆ์งธ ๊บผ๋ฅผ ์„ ํƒํ•ด์„œ ์„ค์น˜ํ• ๊ฒ๋‹ˆ๋‹ค. 

์„ค์น˜ ์œ„์น˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธํŒ…์ด ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ INSTALL ๋ฒ„ํŠผ์„ ๊พน ๋ˆŒ๋Ÿฌ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ Java ๊ฒฝ๋กœ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค๋ฉด Java ์„ค์น˜๊ฐ€ ์ œ๋Œ€๋กœ ์•ˆ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋ฏ€๋กœ ํ™•์ธ์„ ํ•ด๋ณด์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์„ค์น˜๊ฐ€ ์ง„ํ–‰๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 

์ด๋Ÿฐ ์ €๋Ÿฐ ํŒŒ์ผ๋“ค์„ ์ธํ„ฐ๋„ท์—์„œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„๊ฐ€๋ฉด์„œ ์„ค์น˜๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ค‘๊ฐ„์— ์ด๋Ÿฐ ๋ผ์ด์„ผ์Šค ๋™์˜ ํŒ์—…์ฐฝ์ด ๋œจ๋ฉด "Remember accepted licenses"์— ์ฒดํฌํ•ด์ฃผ๊ณ  "Accept"๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ค๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. "Remember choice"์— ์ฒดํฌํ•ด์ฃผ์‹œ๊ณ , "Accept" ๊ณ ๊ณ ์‹ฑ~

์ด ํ™”๋ฉด์€ ์œˆ๋„์šฐ ์šด์˜์ฒด์ œ์—์„œ๋Š” ์•ˆ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์œผ๋‹ˆ, "์ด๋Ÿฐ ํ™”๋ฉด์€ ์™œ ์•ˆ๋‚˜์˜ค์ง€?"ํ•˜์‹ค ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์œˆ๋„์šฐ์—์„œ๋Š” ๊ทธ๋ƒฅ next, next ํ•˜์‹œ๋ฉด ๋ ๊ฒ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋„ ์ฒดํฌํ•ด์ฃผ๊ณ  "Accept selected" ๊ณ ๊ณ ์‹ฑ~

์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด Launch ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.

์ดํด๋ฆฝ์Šค ์„ค์น˜ ์™„๋ฃŒ ํ™”๋ฉด

์ด์ œ Launch ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์‹คํ–‰์„ ์‹œ์ผœ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

workspace ๊ฒฝ๋กœ ์„ค์ •์ฐฝ

์‹คํ–‰ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์ฐฝ์ด ๋œจ๋Š”๋ฐ ๋ฌด์‹œํ•˜๊ณ  ๊ทธ๋ƒฅ "Launch" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. (๊ฒฝ๋กœ๋Š” ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

welcome ์ฐฝ

welcome ์ฐฝ์ด ๋– ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ์ €๋Ÿฐ ๋ฉ”๋‰ด๊ฐ€ ๋ณด์ด๊ณ  ๋ฐ”๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋‰ด๋„ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด์ œ ๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ”๋กœ "์•ˆ๋…• ํ”„๋กœ์ ํŠธ"์ž…๋‹ˆ๋‹ค.

welcome ์ฐฝ์˜ ์šฐ์ธก์—์„œ "Tutorials"๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

"Create a Hello World application"์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋ญ”๊ฐ€ ๋ฐ”๋‘‘ํŒ์ฒ˜๋Ÿผ ์ƒ๊ธด ๋ณต์žกํ•ด๋ณด์ด๋Š” ํ™”๋ฉด์ด ๋‚˜์™”๋Š”๋ฐ ์‹ ๊ฒฝ๋„๊ณ  ์˜ค๋ฅธ์ชฝ์— ๋ณด์ด๋Š” "์›ฐ์ปด์ฐฝ"๋งŒ ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผํ•˜๊ธฐ์ฒ˜๋Ÿผ ๋˜์–ด์žˆ๋Š”๋ฐ ๋ฒ„ํŠผ๋งŒ ๋ˆ„๋ฅด๋ฉด ์•Œ์•„์„œ ์ด๊ฒƒ์ €๊ฒƒ ํ•ด์ค๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ˆœ์„œ์ž…๋‹ˆ๋‹ค.

Hello World ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ž‘์—… ์ˆœ์„œ๋ฅผ ํ•œ๋ฒˆ ์—ฐ์Šตํ•˜๊ณ 

๋‹ค์Œ์— ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ๋•Œ ๋™์ผํ•œ ์ˆœ์„œ๋กœ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

๊ฐ€์šด๋ฐ ํŒŒ๋ž€์ƒ‰์œผ๋กœ "Click to Begin"์„ ํด๋ฆญํ•ด๋ด…์‹œ๋‹ค.

๋ฐ”๋กœ ์•„๋ž˜์ชฝ์— ์žˆ๋Š” "Open the Java perspective" ๋ฉ”๋‰ด๊ฐ€ ์—ด๋ฆฌ๋ฉด์„œ ์ด๋Ÿฐ์ €๋Ÿฐ ์„ค๋ช…์ด ๋˜ ๋‚˜์˜ต๋‹ˆ๋‹ค.

์„ค๋ช…์€ ์–ด๋ ต์ง€ ์•Š์œผ๋‹ˆ ํ•œ๋ฒˆ ์ฝ์–ด๋ณด๊ณ , "Click to perform"์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

Java Perspective๊ฐ€ ์„ ํƒ๋จ

๋ญ”๊ฐ€ ์‹คํ–‰ํ•˜๋Š” ๋“ฏ ํ•˜๋”๋‹ˆ ์ดํด๋ฆฝ์Šค ์ฐฝ ์šฐ์ƒ๋‹จ์— ์„ ํƒ๋œ ์•„์ด์ฝ˜์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์›๋ž˜ ์ปคํ”ผ์ฝฉ ๋ชจ์–‘์ด ์žˆ๋Š” ์•„์ด์ฝ˜์ด ์„ ํƒ๋˜์–ด์žˆ์—ˆ๋Š”๋ฐ, ์ด์ œ J๋ผ๋Š” ๊ธ€์ž๊ฐ€ ์žˆ๋Š” ์•„์ด์ฝ˜์ด ์„ ํƒ๋˜์–ด์ ธ ์žˆ๋„ค์š”.

๊ทธ๋ฆฌ๊ณ  ์›ฐ์ปด์ฐฝ์—์„œ๋Š” ๋‹ค์Œ ๋‹จ๊ณ„์ธ "Create a Java project" ๋ฉ”๋‰ด๊ฐ€ ์—ด๋ ธ์Šต๋‹ˆ๋‹ค.

์„ค๋ช…์„ ํ•œ๋ฒˆ ์ฝ์–ด๋ณด๊ณ  ๋˜ "Click to perform" ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์ฐฝ

์ž๋ฐ” ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์ฐฝ์ด ๋–ด๋Š”๋ฐ ์—ฌ๊ธฐ์„œ "Project name"๋งŒ ์ž…๋ ฅํ•ด์ฃผ๊ณ  "Finish"๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

์ขŒ์ธก์˜ "Project Explorer" ๋ทฐ์— ์ž…๋ ฅ๋งŒ ํ”„๋กœ์ ํŠธ๋ช…์ด ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ HelloWorld ํ”„๋กœ์ ํŠธ

์ด์ œ ๋‹ค์Œ ๋‹จ๊ณ„์ธ "Create your HelloWorld class" ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์„ค๋ช…์— ์žˆ๋Š”๋Œ€๋กœ ๋”ฐ๋ผํ•˜๊ฑฐ๋‚˜ "Click to perform"์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

HelloWorld ํด๋ž˜์Šค ์ƒ์„ฑ์ฐฝ

ํด๋ž˜์Šค ์ƒ์„ฑ์ฐฝ์ด ๋œจ๋Š”๋ฐ ์—ฌ๊ธฐ์„œ๋Š” "Name"์— "HelloWorld" ์ž…๋ ฅ ํ›„ ์•„๋ž˜์ชฝ์— "public static void main(String[] args)" ์˜†์˜ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ฒดํฌํ•˜๊ณ  "Finish" ํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ HelloWorld ํด๋ž˜์Šค

HelloWorld ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์ขŒ์ธก์˜ Package Explorer ์—๋„ ํŒŒ์ผ์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ ,

๊ฐ€์šด๋ฐ ํ……ํ…… ๋น„์–ด์žˆ๋˜ ์ฐฝ์—๋„ ๋ญ”๊ฐ€๊ฐ€ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. 

์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ž๋ฐ” ๋ฌธ๋ฒ•์— ๊ธฐ์ดˆํ•œ ์†Œ์Šค์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์ž, ์ด์ œ ์ฒ˜์Œ์œผ๋กœ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณผ ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค.

์›ฐ์ปด์ฐฝ์˜ ์„ค๋ช…๋Œ€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ์ถœ๋ ฅ๋ฌธ์„ ํ•˜๋‚˜ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.

Hello world! ์ถœ๋ ฅ๋ฌธ ์ž‘์„ฑ

์œ„ ์ฒ˜๋Ÿผ ํ•œ์ค„์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์›ฐ์ปด์ฐฝ ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์˜ ์„ค๋ช…์„ ๋”ฐ๋ผ์„œ ์‹คํ–‰ํ•ด๋ด…๋‹ˆ๋‹ค.

HelloWorld ์‹คํ–‰ํ•˜๊ธฐ
HelloWorld ์‹คํ–‰ ๊ฒฐ๊ณผ

HelloWorld์— ์ž‘์„ฑํ•œ ์ถœ๋ ฅ๋ฌธ์— ๋”ฐ๋ผ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ HelloWorld ํŠœํ† ๋ฆฌ์–ผ์˜ ๋์ž…๋‹ˆ๋‹ค.

 

์šฐ๋ฆฌ๋Š” ํ•˜๋‚˜๋งŒ ๋” ํ•ด๋ณด์ฃ .

System.out.println("Hello world!");

์—ฌ๊ธฐ์„œ "Hello world!" ๋ฅผ "์•ˆ๋…• ํ”„๋กœ์ ํŠธ ์„ฑ๊ณต" ์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์ถœ๋ ฅํ• ๊ฒ๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

System.out.println("์•ˆ๋…• ํ”„๋กœ์ ํŠธ ์„ฑ๊ณต");

์ด์ œ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋ณด์„ธ์š”. 

์•„๋ž˜์ฒ˜๋Ÿผ ๊ฒฐ๊ณผ๊ฐ€ ์ž˜ ๋‚˜์˜ค๋ฉด ๋ฉ๋‹ˆ๋‹ค. 

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ ์˜ค์…จ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์€ ์ด์ œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 

 

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” JDK ์„ค์น˜์™€ ์ดํด๋ฆฝ์Šค IDE ์„ค์น˜ ๊ทธ๋ฆฌ๊ณ  ํ—ฌ๋กœ์›”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ ๊นŒ์ง€

๋ฌด์ž‘์ • ๋”ฐ๋ผํ•ด๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๊ธฐ๋ณธ์ ์ธ ์ค€๋น„๋Š” ๋ชจ๋‘ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค.

 

๋‹ค์Œ ์‹œ๊ฐ„๋ถ€ํ„ฐ๋Š” ์ž๋ฐ”์–ธ์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ง€๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์†Œ์Šค ์ฝ”๋“œ ์ผ๋ถ€

์„œ๋ฌธ

๋‚˜๋Š” ์ด ๊ธ€์„ ์“ฐ๋Š” ์ง€๊ธˆ 7๋…„์ฐจ ์ž๋ฐ” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์ด๋‹ค.

๋‚˜๋Š” ์ž๋ฐ”๋ฅผ ์ œ๋Œ€๋กœ ๊ณต๋ถ€ํ•˜์ง€๋„ ์•Š๊ณ  ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์—ˆ๊ณ , ๊ฐœ๋ฐœ์ž๊ฐ€ ๋œ์ง€ 5๋…„์ด ์ง€๋‚˜์„œ์•ผ ์ฑ…์„ ์ฝ์–ด๋ดค๋‹ค.

์ˆ˜๋งŽ์€ ์ฑ…๋“ค์ด ์žˆ์—ˆ๊ณ  ๊ทธ ์ค‘ ์ œ์ผ ์œ ๋ช…ํ•œ ๋‚จ๊ถ์„ฑ๋‹˜์˜ ์ฑ…๊ณผ ์œค์„ฑ์šฐ๋‹˜์˜  ์ฑ…์„ ์‚ฌ์„œ ํ›‘์–ด๋ณด์•˜๋‹ค.

์ฑ…์€ ๋„ˆ๋ฌด ๋‘๊บผ์› ๊ณ  ๋‹ค์‹œ๊ธˆ ๊นŒ๋จน๊ณ  ์žˆ๋˜ ๊ธฐ์ดˆ์ง€์‹์„ ํ™•์ธํ•˜๋Š” ๊ธฐํšŒ๊ฐ€ ๋˜์—ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ํ•œ ํ•™์ƒ์„ ๊ฐ€๋ฅด์น˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ๋น„์ „๊ณต์ž๋ผ ์ฑ…์˜ ๋‚ด์šฉ์„ ์ดํ•ดํ•˜๋Š”๋ฐ ํž˜๋“ค์–ดํ–ˆ๋‹ค.

์–ธ์  ๊ฐ„ ๋‚˜๋„ ์ฑ…์„ ๋‚ด๋ด์•ผ์ง€๋ผ๋Š” ์ƒ๊ฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ํ„ฐ๋ผ ์ด์ฐธ์— ์ฑ…์˜ ๊ธฐ์ดˆ๊ฐ€ ๋ ๋งŒํ•œ ๊ฐ•์˜๋ฅผ ์—ฌ๊ธฐ์„œ ํ•ด๋ณผ๊นŒ ํ•œ๋‹ค.

์ผ๋ฐ˜์ธ๋“ค, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋ ค๋Š” ๋น„์ „๊ณต์ž๋“ค, ๊ทธ๋ฆฌ๊ณ  ์–ด๋ฆฐ ํ•™์ƒ๋“ค์ด ์ฝ์–ด๋„ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด์šฉ์œผ๋กœ ๊ฐ•์˜๋ฅผ ํ•˜๋ ค ํ•œ๋‹ค.

๋‚ด ์•„์ด๊ฐ€ ๋‚˜์ค‘์— ์ปค์„œ๋„ ์ž๋ฐ”๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค๋ฉด ์ฝ์–ด๋ณด๋„๋ก ์ถ”์ฒœํ•  ์ˆ˜ ์žˆ์„ ์ •๋„์˜ ํ€„๋ฆฌํ‹ฐ๋ฅผ ๊ฐ–๋Š” ๋‚ด์šฉ์œผ๋กœ ๋ง์ด๋‹ค.

๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ์‰ฝ๊ฒŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์„์ง€ ๋งŽ์€ ๊ณ ๋ฏผ์„ ํ•ด์•ผํ•  ๊ฒƒ์ด๊ธฐ์— ๊ฐ•์˜๊ฐ€ ๋นจ๋ฆฌ ์ง„ํ–‰๋˜๊ธฐ๋Š” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์œผ๋‚˜ ์กฐ๊ธˆ์”ฉ ๊พธ์ค€ํžˆ ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

 

 

์˜ค๋Š˜์€ ๊ทธ 1์ผ์ฐจ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ์–˜๊ธฐ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ž๋ฐ”๋ž€?

์„ธ์ƒ์—๋Š” ๋งŽ์€ ์–ธ์–ด๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ๊ตญ์–ด, ์ค‘๊ตญ์–ด, ์˜์–ด, ์ผ๋ณธ์–ด, ์ŠคํŽ˜์ธ์–ด, ๋ถˆ์–ด, ๋…์–ด ๋“ฑ๋“ฑ ๋ง์ด์ฃ .

ํ•œ๊ตญ์‚ฌ๋žŒ๋“ค์€ ํ•œ๊ตญ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ผ๋ณธ์‚ฌ๋žŒ๋“ค์€ ์ผ์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ 3๊ฐœ๊ตญ์–ด 4๊ฐœ๊ตญ์–ด๋ฅผ ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ณธ์–ด๋Š” ํ•œ๊ตญ์–ด์™€ ๋ฌธ๋ฒ•์ด ์œ ์‚ฌํ•ด์„œ ์‰ฝ๊ณ , ์˜์–ด๋Š” ๋ฌธ๋ฒ•์ด ๋‹ฌ๋ผ ๋ฐฐ์šฐ๊ธฐ ์–ด๋ ต๋‹ค๊ณ ๋“ค ํ•ฉ๋‹ˆ๋‹ค.

์–ธ์–ด๋งˆ๋‹ค ํŠน์ • ํ‘œํ˜„์„ ํ•  ๋•Œ ์ข€๋” ๊ณต๊ฐ์ด ๊ฐ€๋Š” ๋ฌธ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ๊ตญ์–ด๋กœ ์ง์—ญ ๋˜๋Š” ์˜์—ญํ•ด๋„ ์˜์–ด์˜ ํŠน์ • ๋ฌธ์žฅ์˜ ๋Š๋‚Œ์„ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜๊ธฐ๋Š” ํž˜๋“ค ๋•Œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ .

 

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—๋„ ๊ทธ๋Ÿฌํ•œ ๋‚ด์šฉ์ด ๋”ฑ ๋“ค์–ด๋งž์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”๋Š” ์ˆ˜๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด(์„ธ๊ณ„ ๊ฐ๊ตญ์˜ ์–ธ์–ด)๋“ค ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. 

์ž๋ฐ” ๊ฐœ๋ฐœ์ž(ํ•œ๊ตญ์ธ)๋“ค์€ ์ž๋ฐ”(ํ•œ๊ตญ์–ด)๋กœ ๊ฐœ๋ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๊ตญ์–ด๋Š” ํ•œ๊ตญ์–ด์ด์ง€๋งŒ 3๊ฐœ๊ตญ์–ด, 4๊ฐœ๊ตญ์–ด๋ฅผ ํ•  ์ค„ ์•„๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žˆ๋“ฏ์ด,

์ž๋ฐ” ๊ฐœ๋ฐœ์ž๋“ค๋„ ์ž๋ฐ”๋งŒ ํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํŒŒ์ด์ฌ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ, C# ๋“ฑ์˜ ์–ธ์–ด๋ฅผ ์ œ2์™ธ๊ตญ์–ด์ฒ˜๋Ÿผ ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์™€ ๋ฌธ๋ฒ•์ด ์œ ์‚ฌํ•œ ์–ธ์–ด๋Š” ์ž๋ฐ”๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ๋Š” learning curve๊ฐ€ ๋‚ฎ์ง€๋งŒ, ๋„ˆ๋ฌด ๋‹ค๋ฅธ ์–ธ์–ด๋Š” ์ ์‘ํ•˜๊ธฐ๊ฐ€ ํž˜๋“ค์ฃ .

๋งˆ์น˜ ํ•œ๊ตญ์–ด์™€ ์ผ๋ณธ์–ด, ํ•œ๊ตญ์–ด์™€ ์˜์–ด์˜ ์ฐจ์ด์ฒ˜๋Ÿผ ๋ง์ด์ฃ .

์ž๋ฐ”๋กœ๋Š” ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฌ์šด ๊ธฐ๋Šฅ์ด ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋Š” ๊ตฌํ˜„ํ•˜๊ธฐ ํž˜๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์‚ฌ๋žŒ๋“ค์€ ์–ธ์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ์†Œํ†ต์„ ํ•ฉ๋‹ˆ๋‹ค.

์–ดํœ˜๋ ฅ์ด ์ข‹์€ ์‚ฌ๋žŒ์ด ์žˆ๊ณ  ์•ˆ์ข‹์€ ์‚ฌ๋žŒ๋„ ์žˆ์ฃ .

๋Œ€ํ™”์˜ ๋…ผ๋ฆฌ๊ฐ€ ํ™•์‹คํžˆ ์žกํ˜€์žˆ๋Š” ์‚ฌ๋žŒ๋„ ์žˆ๊ณ  ๋…ผ๋ฆฌ๋Š” ์—†๊ณ  ์•ž๋’ค์—†๋Š” ๋Œ€ํ™”๋ฅผ ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๋“ค์€ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์†Œํ†ต์„ ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์–ธ์–ด์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฌธ๋ฒ•์„ ๋งŽ์ด ์•Œ๊ณ ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋„ ์žˆ๊ณ  ๊ธฐ์ดˆ์ ์ธ ๊ฒƒ๋งŒ ์•Œ๊ณ ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋„ ์žˆ์ฃ .

๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ’€๋•Œ์—๋„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•œ ๊ฐœ๋ฐœ์ž๋„ ์žˆ๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์ž๋ฐ”๋ผ๋Š” ์–ธ์–ด๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์ œ2์™ธ๊ตญ์–ด์™€ ๊ฐ™์€ ์กด์žฌ์ž…๋‹ˆ๋‹ค.

 

์†Œ์Šค์ฝ”๋“œ์™€ ์†Œ์„ค

์ œ ์™€์ดํ”„๋Š” ์ œ๊ฐ€ IDE(๊ฐœ๋ฐœํˆด)ํ™”๋ฉด์— ์ฝ”๋”ฉ์„ ํ•˜๋Š” ๋ชจ์Šต์„ ๋ณด๊ณ , "์ด๊ฒŒ ๋ญ์•ผ? ๋„๋Œ€์ฒด ๋ญ๋ผ๊ณ  ์“ฐ๋Š”๊ฑด์ง€ ํ•˜๋‚˜๋„ ๋ชจ๋ฅด๊ฒ ๋„ค. ์ด๋Ÿฐ๊ฒŒ ์ดํ•ด๊ฐ€ ๋˜?" ๋ผ๊ณ  ์งˆ๋ฌธ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋‹น์—ฐํžˆ ๊ทธ๋Ÿฐ ๋ฐ˜์‘์ด ๋‚˜์˜ฌ ์ˆ˜ ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. ์™€์ดํ”„ ์ž…์žฅ์—์„œ๋Š” ์ œ๊ฐ€ ์˜ค์ง€์˜ ์ธ๋””์–ธ์ด ์‚ฌ์šฉํ•˜๋Š” ์–ธ์–ด๋กœ ๊ธ€์„ ์“ฐ๊ณ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์งˆ ํ…Œ๋‹ˆ๊นŒ์š”. 

๊ฐœ๋ฐœ์ž๋“ค์€ ์ž์‹ ์ด ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด(์ œ2์™ธ๊ตญ์–ด)๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž์‹ ๋“ค๋งŒ์˜ ๊ธ€์„ ์จ๋‚ด๋ ค ๊ฐ‘๋‹ˆ๋‹ค. ๊ฐ™์€ ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ ๊ฐœ๋ฐœ์„ ํ•œ๋‹คํ•ด๋„ ๊ฐœ๋ฐœ์ž๋“ค ์„ฑํ–ฅ์— ๋”ฐ๋ผ 1. ํšจ์œจ์„ฑ์€ ์กฐ๊ธˆ ๋–จ์–ด์ง€์ง€๋งŒ ๊ฐ€๋…์„ฑ์ด ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๊ณ , 2. ํšจ์œจ์„ฑ์€ ๊ทน๋Œ€ํ™”ํ–ˆ์ง€๋งŒ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ํž˜๋“  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ €๋Š” ์ „์ž๋ฅผ ์ง€ํ–ฅํ•˜๊ณ  ํ›„๋ฐฐ๋“ค์—๊ฒŒ๋„ ์ „์ž๋ฅผ ์ง€ํ–ฅํ•˜๋„๋ก ์กฐ์–ธํ•ฉ๋‹ˆ๋‹ค.

 

์‹œ์ธ, ์†Œ์„ค์ž‘๊ฐ€, ์ˆ˜ํ•„๊ฐ€ ๋“ฑ ๊ธ€์„ ์“ฐ๋Š” ๋ถ„๋“ค์ด ๋‹จ์–ด ํ•˜๋‚˜ํ•˜๋‚˜์— ๊ณ ์‹ฌ์„ ํ•˜๋“ฏ ์ €๋„ ์ฝ”๋”ฉ์„ ํ•  ๋•Œ ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๋”๋ผ๋„ ์ข€ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํšจ์œจ์ ์ธ ์ฝ”๋”ฉ์„ ํ•˜๋ ค๊ณ  ๋ง์ด์ฃ . ์ข‹์€ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ธฐ์œ„ํ•ด ์ฒจ์‚ญ์„ ๋ฐ›๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ๊ฐœ๋ฐœ์ž๋“ค๋„ ์ฝ”๋“œ๋ฆฌ๋ทฐ ์‹œ๊ฐ„์„ ํ†ตํ•ด ๊ณ ๊ธ‰๊ฐœ๋ฐœ์ž๋“ค์˜ ์กฐ์–ธ์„ ๋“ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ด๋ ‡๊ฒŒ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. "ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์จ๋‚ด๋ ค๊ฐ€๋Š” ๊ธ€์ด๋‹ค"๋ผ๊ณ  ๋ง์ด์ฃ . ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ์งง์ง€๋งŒ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ์‹œ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ๊ณ , ์ข€ ๊ธธ์–ด๋„ ์ˆ ์ˆ  ์ฝ์–ด๋‚ด๋ ค๊ฐˆ ์ˆ˜ ์žˆ๋Š” ํŒํƒ€์ง€ ์†Œ์„ค์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๊ธ€์„ ์ž‘์„ฑํ•˜๋Š๋ƒ๋Š” ์ˆœ์ „ํžˆ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋ชซ์ด์ฃ . 

 

 

Wrap Up

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ž€ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ์–ธ์–ด๋กœ ์ผ์–ด, ์ค‘๊ตญ์–ด, ์˜์–ด์™€ ๊ฐ™์€ ์ œ2์™ธ๊ตญ์–ด์˜ ํ•˜๋‚˜๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—๋Š” ์—ฌ๋Ÿฌ ์–ธ์–ด๋“ค์ด ์กด์žฌํ•˜๋Š”๋ฐ ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ž๋ฐ”(java)๋‹ค.

 

๊ณ ๊ธ‰๋‚ด์šฉ ๋ณด์ถฉ

์ž๋ฐ”๋Š” ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ JVM(Java Virtual Machine)์ด๋ผ๋Š” ๊ฐ€์ƒ๋จธ์‹  ์œ„์—์„œ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์— ํ”Œ๋žซํผ(OS, ์šด์˜์ฒด์ œ)์— ์˜์กด์ ์ด์ง€ ์•Š์ฃ . Linux๊ณ„์—ด์—์„œ๋„ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๊ณ , Windows์—์„œ๋„ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด ์•ˆ๋“œ๋กœ์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ์ž๋ฐ”๋กœ ๊ฐœ๋ฐœํ•ฉ๋‹ˆ๋‹ค(์š”์ฆ˜์€ Kotlin์ด๋ผ๋Š” ์–ธ์–ด๋„ ๋งŽ์ด ์‚ฌ์šฉํ•˜์‹œ๋”๊ตฐ์š”). ๋˜ํ•œ, JVM์ด ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. C์–ธ์–ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผ์„ ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ฆฌ๋„ ์ง์ ‘ ํ•ด์•ผํ•˜์ฃ .

์ž๋ฐ”๋Š” ์›น๊ฐœ๋ฐœ์— ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Python(ํŒŒ์ด์ฌ)์€ ๋น…๋ฐ์ดํ„ฐ ์˜์—ญ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ , C, C++์€ ์ž„๋ฒ ๋””๋“œ ์˜์—ญ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋ฉฐ, C#์€ ๊ฒŒ์ž„๊ฐœ๋ฐœ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.