2 ๋ถ„ ์†Œ์š”

๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ญ˜๊นŒ?

๋™์˜์ƒ ๊ฐ•์˜๋ฅผ ๋“ฃ๋˜ ์ค‘, ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์ด ๋‚˜์™”๋‹ค.
๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ญ”์ง€ ๋ชฐ๋ผ์„œ ์ฐพ์•„๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

๋™์‹œ์„ฑ ๋ฌธ์ œ๋ž€

๋™์‹œ์„ฑ ๋ฌธ์ œ๋ž€ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ ๊ฐ’์„ โ€œ๋ณ€๊ฒฝโ€ํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋งํ•œ๋‹ค.
์ด๋Ÿฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ์— ์ ‘๊ทผํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋ž˜ํ”ฝ์ด ์ ์€ ์ƒํ™ฉ์—์„œ๋Š” ํ™•๋ฅ ์ƒ ์ž˜ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์ง€๋งŒ, ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์•„์งˆ ์ˆ˜๋ก ๋ฐœ์ƒ ํ™•๋ฅ ์ด ๋†’์•„์ง„๋‹ค.
ํŠนํžˆ ์Šคํ”„๋ง ๋นˆ ์ฒ˜๋Ÿผ โ€œ์‹ฑ๊ธ€ํ†คโ€ ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉฐ ์‚ฌ์šฉํ•  ๋•Œ ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์กฐ์‹ฌํ•˜์ž!

์ฐธ๊ณ 
๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ์ง€์—ญ๋ณ€์ˆ˜์—์„œ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
์™œ๋ƒํ•˜๋ฉด ์ง€์—ญ๋ณ€์ˆ˜๋Š” ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ! ๊ทธ๋ฆฌ๊ณ  static๊ฐ™์€ ๊ณต์šฉ ํ•„๋“œ์— ์ ‘๊ทผํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ.
ํ•˜์ง€๋งŒ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ๊ฐ’์„ ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ , ์–ด๋””์„ ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์•ผ ๋ฐœ์ƒํ•œ๋‹ค!

์˜ˆ์ œ์ฝ”๋“œ

package hello.advanced.trace.threadlocal;

import hello.advanced.trace.threadlocal.code.FieldService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

@Slf4j
public class FieldServiceTest {

    private FieldService fieldService = new FieldService();

    @Test
    void field() {
        log.info("main start");
        Runnable userA = () -> {
            fieldService.logic("userA");
        };
        Runnable userB = () -> {
            fieldService.logic("userB");
        };

        Thread threadA = new Thread(userA);
        threadA.setName("thread A");

        Thread threadB = new Thread(userB);
        threadB.setName("thread B");

        threadA.start();
//        sleep(2000);    // ๋™์‹œ์„ฑ ๋ฌธ์ œ ๋ฐœ์ƒ x
        sleep(100);
        threadB.start();

        sleep(3000);    // ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ ๋Œ€๊ธฐ
        log.info("main exit");

    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}

sleep(2000);์œผ๋กœ ํ•˜๋ฉด ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
ํ•˜์ง€๋งŒ sleep(100);์œผ๋กœ ํ•˜๋ฉด ๋งค์šฐ ์งง์€ ์‹œ๊ฐ„ ๋™์•ˆ๋งŒ sleep์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

[๊ฒฐ๊ณผ]

00:51:26.619 [Test worker] INFO hello.advanced.trace.threadlocal.FieldServiceTest - main start
00:51:26.622 [thread A] INFO hello.advanced.trace.threadlocal.code.FieldService - ์ €์žฅ name=userA --> nameStore=null
00:51:26.727 [thread B] INFO hello.advanced.trace.threadlocal.code.FieldService - ์ €์žฅ name=userB --> nameStore=userA
00:51:27.628 [thread A] INFO hello.advanced.trace.threadlocal.code.FieldService - ์กฐํšŒ namrStore=userB
00:51:27.733 [thread B] INFO hello.advanced.trace.threadlocal.code.FieldService - ์กฐํšŒ namrStore=userB
00:51:29.733 [Test worker] INFO hello.advanced.trace.threadlocal.FieldServiceTest - main exit

์›๋ž˜๋Š” nameStore์— userA๊ฐ€ ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š”๋ฐ, sleep์‹œ๊ฐ„์ด ๋งค์šฐ ์งง์•„ userA์ž‘์—…์ด ๋๋‚˜๊ธฐ๋„ ์ „์— userB๊ฐ€ ์น˜๊ณ  ๋“ค์–ด์™”๋‹ค.
๊ทธ๋ž˜์„œ nameStore์— ์žˆ๋Š” ์ตœ์‹  ๊ฐ’์€ userB์ด๊ณ , userA์˜ ์ž‘์—…์ด ์™„๋ฃŒ๋˜์–ด return์„ ๋ฐ›๋Š”๋ฐ nameStore์— ๋“ค์–ด์žˆ๋Š” ๊ฐ’์€ userB๋ผ์„œ userA๊ฐ€ userB๋ฅผ ๋ฆฌํ„ด๋ฐ›๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ˆœ์„œ๋Œ€๋กœ ์ •๋ฆฌ

  1. threadA๋Š” userA๋ฅผ nameStore์— ์ €์žฅ.
  2. threadB๋Š” userB๋ฅผ nameStore์— ์ €์žฅ.
  3. threadA๋Š” userB๋ฅผ nameStore์— ์กฐํšŒ.
  4. threadB๋Š” userB๋ฅผ nameStore์— ์กฐํšŒ.

๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ - ThreadLocal

ThreadLocal์€ ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ €์žฅ์†Œ ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์‰ฝ๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด, ๋ฌผ๊ฑด์„ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ์ฐฝ๊ตฌ๋ฅผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋ฌผ๊ฑด์„ ๋ณด๊ด€ํ•˜๊ฒŒ ๋˜๋ฉด, ์ง์›์ด ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋ฌผ๊ฑด์„ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ณ„ ๋ณด๊ด€ํ•จ์— ๋ฌผ๊ฑด์„ ๋ณด๊ด€ํ•˜๊ณ  ๊บผ๋‚ธ๋‹ค.

์Šค๋ ˆ๋“œ ๋กœ์ปฌ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋‚ด๋ถ€ ์ €์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ํ•„๋“œ์— ์ ‘๊ทผํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.

์ฐธ๊ณ 
์ž๋ฐ”์—์„œ๋Š” ์–ธ์–ด ์ฐจ์›์—์„œ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด java.lang.ThreadLocalํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•จ!

ThreadLocal ์‚ฌ์šฉ๋ฒ•

  • ๊ฐ’ ์ €์žฅ: ThreadLocal.set()
  • ๊ฐ’ ์กฐํšŒ: ThreadLocal.get()
  • ๊ฐ’ ์‚ญ์ œ: ThreadLocal.remove()

์ฃผ์˜: ํ•ด๋‹น ์Šค๋ ˆ๋“œ๊ฐ€ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๊ณ  ๋‚˜๋ฉด ThreadLocal.remove()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์— ์ €์žฅ๋œ ๊ฐ’์„ ์ œ๊ฑฐํ•ด์ฃผ์–ด์•ผ ํ•จ!

๊ฒฐ๊ณผ์ ์œผ๋กœ!
์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๋•๋ถ„์— ์Šค๋ ˆ๋“œ ๋ณ„๋กœ ๋ณ„๋„์˜ ์ €์žฅ๊ณต๊ฐ„์„ ๊ฐ–๊ฒŒ ๋˜์—ˆ๋‹ค! -> ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ!

ThreadLocal ์ฃผ์˜์‚ฌํ•ญ

์Šค๋ ˆ๋“œ ๋กœ์ปฌ์˜ ๊ฐ’์„ ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋ƒฅ ๋‘๋ฉด WAS(ํ†ฐ์บฃ)์ฒ˜๋Ÿผ ์Šค๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

[์‚ฌ์šฉ์žA์˜ ์š”์ฒญ]
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-02-20 แ„‹แ…ฉแ„’แ…ฎ 6 22 56

  • ์‚ฌ์šฉ์ž A๊ฐ€ ์ €์žฅ http์š”์ฒญ์„ ๋ณด๋ƒ„
  • WAS๋Š” ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜ ์กฐํšŒํ•จ
  • ์Šค๋ ˆ๋“œ thread-A๊ฐ€ ํ• ๋‹น๋จ
  • thread-A๋Š” ์‚ฌ์šฉ์ž A์˜ ์ •๋ณด๋ฅผ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์— ์ €์žฅํ•จ
  • ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์˜ thread-A ์ „์šฉ ์ €์žฅ์†Œ์— ์‚ฌ์šฉ์ž A์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•จ

[์‚ฌ์šฉ์žA์˜ ์š”์ฒญ ์ข…๋ฃŒ]
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-02-20 แ„‹แ…ฉแ„’แ…ฎ 6 27 35

  • ์‚ฌ์šฉ์žA์˜ HTTP ์‘๋‹ต์ด ๋๋‚จ
  • WAS๋Š” ์‚ฌ์šฉ์ด ๋๋‚œ thread-A ๋ฅผ ์“ฐ๋ ˆ๋“œ ํ’€์— ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋น„์šฉ์€ ๋น„์‹ธ๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ๋ ˆ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ , ๋ณดํ†ต ์“ฐ๋ ˆ๋“œ ํ’€์„ ํ†ตํ•ด์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•จ
  • thread-A ๋Š” ์“ฐ๋ ˆ๋“œํ’€์— ์•„์ง ์‚ด์•„์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์˜ thread-A ์ „์šฉ ๋ณด๊ด€์†Œ์— ์‚ฌ์šฉ์žA ๋ฐ์ดํ„ฐ๋„ ํ•จ๊ป˜ ์‚ด์•„์žˆ๊ฒŒ ๋œ๋‹ค.

[์‚ฌ์šฉ์žB์˜ ์š”์ฒญ]
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-02-20 แ„‹แ…ฉแ„’แ…ฎ 6 26 07

  • ์‚ฌ์šฉ์žB๊ฐ€ ์กฐํšŒ๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด HTTP ์š”์ฒญ์„ ๋ณด๋ƒ„
  • WAS๋Š” ์“ฐ๋ ˆ๋“œ ํ’€์—์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜ ์กฐํšŒํ•จ
  • ์“ฐ๋ ˆ๋“œ thread-A ๊ฐ€ ํ• ๋‹น๋˜์—ˆ๋‹ค. (๋ฌผ๋ก  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ• ๋‹น๋  ์ˆ˜ ๋„ ์žˆ๋‹ค.)
  • ์ด๋ฒˆ์—๋Š” ์กฐํšŒํ•˜๋Š” ์š”์ฒญ์ด๋‹ค. thread-A ๋Š” ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  • ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์€ thread-A ์ „์šฉ ๋ณด๊ด€์†Œ์— ์žˆ๋Š” ์‚ฌ์šฉ์žA ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉ์žA ๊ฐ’์ด ๋ฐ˜ํ™˜๋œ๋‹ค.
  • ์‚ฌ์šฉ์žB๋Š” ์‚ฌ์šฉ์žA์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค.

์œ„์ฒ˜๋Ÿผ ๋ณด์•ˆ์ ์ธ ์ธก๋ฉด์—์„œ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์‚ฌ์šฉ์žA์˜ ์š”์ฒญ์ด ๋๋‚  ๋•Œ ๋ฐ˜๋“œ์‹œ ThreadLocal.remove()๋ฅผ ํ†ตํ•ด ๊ผญ ์ œ๊ฑฐํ•ด์ฃผ์ž.

ํƒœ๊ทธ: ,

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ