๐Ÿ˜ˆThread Safety ์‚ดํŽด๋ณด๊ธฐ๐Ÿ‘€

์ฝ”์ฝ”๋”ฉ๋”ฉยท2022๋…„ 4์›” 24์ผ
0

JAVA Basic

๋ชฉ๋ก ๋ณด๊ธฐ
5/7

๊ฐœ์š”

  • ์›น ์„œ๋ฒ„๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ๋ณ‘๋ ฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•œ ์ดํ•ด๋Š” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • Thread Safety๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š” ์ƒํ™ฉ์€ ๊ฐœ๋ฐœ์ž์˜ ๊ณจ์น˜๋ฅผ ์•„ํ”„๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

  • ์–ด๋Š ๋•Œ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค๊ฐ€๋„, ํƒ€์ด๋ฐ์— ๋”ฐ๋ผ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

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

  • ์Šค์Šค๋กœ๋„ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•œ ๋ฒ„๊ทธ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ Thread Safety์— ๋Œ€ํ•ด ์กฐ์‚ฌํ•ด๋ด…๋‹ˆ๋‹ค.

  • ๋ฐ”์˜์‹  ๋ถ„๋“ค์€ ๋งˆ์ง€๋ง‰ ์ •๋ฆฌ ๋ถ€๋ถ„์„ ๋ณด์‹œ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชฉํ‘œ

๐Ÿš€ Thread Safety์˜ ์ •์˜์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.
๐Ÿš€ ๊ฐ„๋‹จํ•˜๊ฒŒ JVM Runtime Data Aread์™€ ๊ณต์œ  ์ž์›์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.
๐Ÿš€ ๋‹จ์ผ์—ฐ์‚ฐ๊ณผ ๋ณตํ•ฉ์—ฐ์‚ฐ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.
๐Ÿš€ ๊ฒฝ์Ÿ์กฐ๊ฑด์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.
๐Ÿš€ Thread Unsafetyํ•œ ์ƒํ™ฉ์„ ์‚ดํŽด๋ณด๊ณ  ๊ณ ์ณ๋ด…๋‹ˆ๋‹ค.

1. Thread Safety๋ž€?

  • ์ž๋ฐ”๋Š” Multi Thread Progamming Language์ž…๋‹ˆ๋‹ค.

  • Multi Threading๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•˜์ž๋ฉด โ€œ์—ฌ๋Ÿฌ Thread๊ฐ€ ํ•œ Process์˜ ์ž์›์„ ๊ณต์œ ํ•˜๋ฉฐ ๋™์ž‘ํ•˜๋Š” ๊ฒƒโ€ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฆ‰, ํ•œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ์—ฌ๊ธฐ์„œ ๋™์‹œ๋ผ๋Š” ์˜๋ฏธ๋Š” ํŒŒ๊ณ ๋“ค ์ˆ˜๋ก ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Single Core Processor์—์„œ๋Š” ์‹ค์ œ๋กœ ์—ฌ๋Ÿฌ ์ผ์„ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ ๋™์‹œ์— ๊ทธ ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์‚ฌ๋žŒ์ด ๋Š๋ผ์ง€ ๋ชปํ•  ์ •๋„๋กœ ๋น ๋ฅด๊ฒŒ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉด์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  Multi Core Processor์—์„œ๋Š” ์‹ค์ œ๋กœ ๋™์‹œ์— Task๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๐Ÿ‘‰ ๋™์‹œ์„ฑ๊ณผ ๋ณ‘๋ ฌ์„ฑ์˜ ์ฐจ์ด ๐Ÿ‘ˆ ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ดํ•ดํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.

  • Process์˜ ํ•œ ๊ณต์œ  ์ž์›์— ์—ฌ๋Ÿฌ Thread์—์„œ ์ ‘๊ทผํ•˜๋ฉด ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Thread Safety๋ž€ โ€œProcess์˜ ํ•œ ๊ณต์œ  ์ž์›์— ์—ฌ๋Ÿฌ Thread๊ฐ€ ์ ‘๊ทผํ•˜์—ฌ ์—ฐ์‚ฐ์„ ํ•  ๋•Œ, ํ•ญ์ƒ ๊ทธ ์—ฐ์‚ฐ๊ฒฐ๊ณผ์˜ ๊ธฐ๋Œ€๊ฐ’์ด ์ผ๊ด€์„ฑ์„ ๊ฐ€์ง์„ ๋ณด์žฅํ•˜๋Š” ๊ฒƒโ€์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ์‹œ ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@ThreadSafe
public class Calculator{
	public int plus(int a, int b){
		return a + b;
	}
}
  • Calculator์˜ plus ๋ฉ”์†Œ๋“œ๋Š” ๋‘ ์ธ์ž๋ฅผ ๋ฐ›์•„ ๋”ํ•œ ํ›„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • Calculator์˜ Instance์— ์—ฌ๋Ÿฌ Thread๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋”๋ผ๋„ ํ•ญ์ƒ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • int a์™€ int b๋Š” Stack์˜์—ญ์˜ ๋ณ€์ˆ˜์ด๋ฏ€๋กœ ๋‹ค๋ฅธ Thread์—์„œ ๊ฐ„์„ญํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ด๋ ‡๊ฒŒ Thread Safety๋Š” ์ผ๊ด€์„ฑ(ํ˜น์€ ์ •ํ™•์„ฑ)์˜ ๊ฐœ๋…๊ณผ ๊นŠ์€ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
  • ์ผ๊ด€์„ฑ์€ "์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์–ด๋–ค ํƒ€์ด๋ฐ์— ์‹คํ–‰ํ•˜๋”๋ผ๋„ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฐ’์ด ์ •ํ™•ํžˆ ๋‚˜์˜ค๋Š” ๊ฒƒ"์ด๋ผ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. Multi Threading ํ™˜๊ฒฝ์—์„œ์˜ Issue

  • JVM์˜ Heap Area์™€ Method Area๋Š” ๋ชจ๋“  Thread์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • JVM์˜ Runtime Data Area์— ๋Œ€ํ•œ ์„ค๋ช…์ด ํ•„์š”ํ•˜์‹  ๊ฒฝ์šฐ ๐Ÿ‘‰ ํ•ด๋‹น ์•„ํ‹ฐํด ๐Ÿ‘ˆ์„ ์ฐธ๊ณ ํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

  • ์ด๋ ‡๊ฒŒ ๋ชจ๋“  Thread์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต์œ  ์ž์›์€ ๊ฒฝ์Ÿ์กฐ๊ฑด์„ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ๊ฒฝ์Ÿ์กฐ๊ฑด์€ ์‰ฝ๊ฒŒ ๋งํ•˜์ž๋ฉด "ํƒ€์ด๋ฐ์ด ์ข‹์ง€ ์•Š์„ ๋•Œ ๊ฒฐ๊ณผ๊ฐ€ ์ž˜๋ชป๋  ๊ฐ€๋Šฅ์„ฑ"์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ์—ญ์‹œ ๋ฐฑ๋ฌธ์ด๋ถˆ์—ฌ์ผ๊ฒฌ ์ž…๋‹ˆ๋‹ค.

public class ChattingRoom{
    private int count = 0;

    public void enter(){
        count++; // ์ฑ„ํŒ…๋ฐฉ์— ๋“ค์–ด์˜ค๋ฉด ์ฐธ๊ฐ€ ์ธ์›์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
    }

    public long getCount(){
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("start");
        final ChattingRoom chattingRoom = new ChattingRoom();
        UserEntrance entrance = new UserEntrance(chattingRoom);
        UserEntrance entrance2 = new UserEntrance(chattingRoom);
        UserEntrance entrance3 = new UserEntrance(chattingRoom);
        entrance.start();
        entrance2.start();
        entrance3.start();
        Thread.sleep(10000);
        System.out.println("์ฑ„ํŒ…๋ฐฉ ์ธ์› ์ˆ˜ = " + chattingRoom.getCount());
        System.out.println("end");
    }
}

public class UserEntrance extends Thread{
    private final ChattingRoom chattingRoom;

    public UserEntrance(ChattingRoom chattingRoom) {
        this.chattingRoom = chattingRoom;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            chattingRoom.enter(); // ์ฆ๊ฐ€!
        }
    }
}

/*
start
์ฑ„ํŒ…๋ฐฉ ์ธ์› ์ˆ˜ = 20891 
end
*/
  • ์ฑ„ํŒ…๋ฐฉ์— ์œ ์ €๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ฐธ์—ฌ์ž ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

  • ํฐ ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ(...) ์œ„ ์ฝ”๋“œ๋Š” ํƒ€์ด๋ฐ์— ๋”ฐ๋ผ์„œ ๋ฒ„๊ทธ๋ฅผ ์ผ์œผํ‚ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜ˆ ๐Ÿ˜ˆ ๐Ÿ˜ˆ

  • 10,000๋ฒˆ ์”ฉ 3๊ฐœ์˜ Thread์—์„œ ChattingRoom๊ฐ์ฒด์˜ count๋ฅผ ์ฆ๊ฐ€์‹œ์ผฐ์œผ๋‹ˆ ๊ฒฐ๊ณผ๋Š” 30,000์ด ๋‚˜์˜ฌ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—‰๋šฑํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”์Šต๋‹ˆ๋‹ค.

  • ์ด๋Ÿฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ ์ด์œ ๋Š” count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ์—ฐ์‚ฐ์˜ ํƒ€์ด๋ฐ์ด ์ข‹์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

  • [count++] ์—ฐ์‚ฐ์€ ๋‹จ์ผ์—ฐ์‚ฐ์œผ๋กœ ๋ณด์ด๊ฒ ์ง€๋งŒ ์‚ฌ์‹ค ๋ณตํ•ฉ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค.

- [count++]์€ ์•„๋ž˜ ์—ฐ์‚ฐ๋“ค์˜ ์กฐํ•ฉ์ด๋‹ค.
- ์—ฐ์‚ฐ 1 : count๋กœ๋ถ€ํ„ฐ ๊ฐ’์„ ์ฝ์–ด์˜จ๋‹ค.
- ์—ฐ์‚ฐ 2 : ์ฝ์–ด์˜จ ๊ฐ’์— 1์„ ๋”ํ•œ๋‹ค
- ์—ฐ์‚ฐ 3 : ๋”ํ•œ ๊ฐ’์„ count์— ์ €์žฅํ•œ๋‹ค. 
  • ์ด๋Ÿฌํ•œ ๋ณตํ•ฉ์—ฐ์‚ฐ์— ๋Œ€ํ•ด์„œ Thread-1, 2, 3์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์—ฐ์‚ฐ์„ ํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค.
- ์ตœ์ดˆ์— count๋Š” 0์ด๋‹ค. 
- Thread-1์ด ์—ฐ์‚ฐ 1, ์—ฐ์‚ฐ 2๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Context Switching ์ผ์–ด๋‚œ๋‹ค.
  ๊ทธ ๋•Œ๋ฌธ์— ์—ฐ์‚ฐ 3์„ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ–ˆ๊ณ  ์•„์ง count๋Š” 0์ด๋‹ค.
- Thread-2๊ฐ€ ์—ฐ์‚ฐ 1์„ ์ˆ˜ํ–‰ํ•œ๋‹ค ์ด ๋•Œ๊นŒ์ง€ count์˜ ๊ฐ’์€ 0์ด๋‹ค. 
  ๊ทธ๋ฆฌ๊ณ  ์—ฐ์‚ฐ 2~3์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. count์˜ ๊ฐ’์€ 1์ด ๋œ๋‹ค.
- ๋‹ค์‹œ Context Switching ์ผ์–ด๋‚œ๋‹ค.
  ์ด์ œ Thread-1์ด ์—ฐ์‚ฐ 3์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์—ฐ์‚ฐ 2๊นŒ์ง€์˜ ๊ฒฐ๊ณผ๋Š” 1์ด์˜€๊ณ , ๊ทธ ๊ฐ’์„ count์— ๋„ฃ๋Š”๋‹ค.
- ๊ฒฐ๊ตญ ๋‘ ๋ฒˆ์˜ ์ฆ๊ฐ€ ์—ฐ์‚ฐ์ด ์žˆ์—ˆ์ง€๋งŒ ๊ฒฐ๊ณผ์ ์œผ๋กœ count์˜ ๊ฐ’์€ 1์ด๋œ๋‹ค.
  ์šฐ๋ฆฌ์˜ ๊ธฐ๋Œ€๊ฐ’์€ 2์˜€์œผ๋‚˜ ์ข‹์ง€ ์•Š์€ ํƒ€์ด๋ฐ ์ฆ‰, ๊ฒฝ์Ÿ์กฐ๊ฑด์— ์˜ํ•ด์„œ ๊ฒฐ๊ณผ ๊ฐ’์ด 1์ผ ์ˆ˜๋„, 2์ผ์ˆ˜๋„ ์žˆ๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ์ผ์–ด๋‚  ์ˆ˜๋ก ๊ธฐ๋Œ€ํ–ˆ๋˜ ๊ฒฐ๊ณผ๋Š” ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค
  • ๋˜ํ•œ ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์ด ๋ช‡ ๋ฒˆ ์ผ์–ด๋‚  ์ง€ ์˜ˆ์ƒ๋„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์šด์ด ์ข‹๋‹ค๋ฉด ์ •์ƒ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜๋„ ์žˆ๊ณ , ๊ฐœ๋ฐœ์ž๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค...! ๐Ÿคฏ ๐Ÿฅต

3. Thread Safety๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š” ์›์ธ

  • ์œ„์˜ ์˜ˆ๋กœ๋ถ€ํ„ฐ ๋ณด๋ฉด ๋ฌด์—‡์ด Thread Safety๋ฅผ ์œ„ํ˜‘ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ ์›์ธ์„ ํฐ ํ‹€์—์„œ ๋‚˜๋ˆ„๋ฉด ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์›์ธ 1. ๊ณต์œ ์ž์›๊ณผ ๋ณตํ•ฉ์—ฐ์‚ฐ(Race Condition)

  • ์—ฌ๊ธฐ์„œ ๊ณต์œ  ์ž์›์ด๋ž€ ๋ชจ๋“  Thread์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ž์›์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋Š” Heap Area์— ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด์˜ Instance Variable๊ณผ Method Area์— ์กด์žฌํ•˜๋Š” Class Variable์ž…๋‹ˆ๋‹ค.
  • ๋‘ ๊ฐ์ฒด๋Š” ๋ชจ๋“  JVM์˜ ๋ชจ๋“  Thread์—์„œ ๊ณต์œ  ๋˜๊ธฐ์— ์–ด๋–ค ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์‹œ ๋™์‹œ์— ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ตญ ์ˆ˜์ •๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์˜ ์ƒํƒœ ๊ฐ’์„ ๊ฐ€์ง€๊ณ , ๋™๊ธฐํ™”๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ด๋Š” ๋™์‹œ์„ฑ ์ด์Šˆ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ ์ž ํ•˜๋Š” ์—ฐ์‚ฐ์ด ์›์ž์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉด ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์˜ Context Switching์ด ์ผ์–ด๋‚˜๋”๋ผ๋„ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฆ‰, ์–ด๋–ค ๋ณตํ•ฉ์—ฐ์‚ฐ์ด ์žˆ๋”๋ผ๋„ ๊ทธ ์—ฐ์‚ฐ์„ ํ•˜๊ธฐ ์ „๊ณผ ํ•œ ํ›„๋กœ๋งŒ ๋‚˜๋ˆ ์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด๋Š” ๋‹จ์ผ์—ฐ์‚ฐ์œผ๋กœ ๋ณด์•„๋„ ๋ฌด๋ฐฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์ด๋Š” ์•”๋ฌต์  ๋ฝ์ด๋‚˜, ๋ช…์‹œ์  ๋ฝ์„ ํ†ตํ•ด์„œ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ๋™๊ธฐํ™”๊ฐ€ ๋˜์–ด์žˆ์ง€ ์•Š์€ ๋ณตํ•ฉ์—ฐ์‚ฐ์€ ๊ฒฝ์Ÿ์กฐ๊ฑด์„ ๊ฐ€์ง€๊ฒŒ ๋˜๊ณ  ์œ„์˜ ์˜ˆ์‹œ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋„๋Œ€์ฒด ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์ด ํŽผ์ณ์ง‘๋‹ˆ๋‹ค.

์›์ธ 2. ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์‹œ์„ฑ(Memory Visibility)

  • ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์‹œ์„ฑ์€ "ํ•œ Thread๊ฐ€ ๊ณต์œ  ์ž์›์„ ๋ณ€๊ฒฝํ–ˆ์„ ๋•Œ ๋‹ค๋ฅธ Thread์—์„œ๋„ ๋ณ€๊ฒฝ๋œ ์ตœ์‹ ๊ฐ’์„ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š๋ƒ"๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ์ด ๋˜ํ•œ ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public class NoVisibility {
    private static boolean ready;
    private static int number;

    private static class ReaderThread extends Thread{
        @Override
        public void run() {
            while (!ready) {
                Thread.yield();
            }
            System.out.println("number = " + number);
        }
    }

    public static void main(String[] args) {
        new ReaderThread().start();
        new ReaderThread().start();
        new ReaderThread().start();
        new ReaderThread().start();
        number = 45;
        ready = true;
    }
}
  • ์œ„ ์ฝ”๋“œ์—์„œ Main Thread๊ฐ€ number์™€ ready์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๋•Œ ReaderThread1~4์—์„œ๋Š” Main Thtread๊ฐ€ ๊ฐ’์„ ๋ฐ”๊พธ๋ƒ์— ๋”ฐ๋ผ์„œ ๋™์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ๋ณดํ†ต ๊ฐ ReaderThread๊ฐ€ while๋ฌธ์„ ๋ฐ˜๋ณตํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€, Main Thread์—์„œ ready๋ฅผ ture๋กœ ๋ฐ”๊พธ๋ฉด while ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•  ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
  • ์•ˆํƒ€๊น๊ฒŒ๊ณ  ์ด ์ฝ”๋“œ๋Š” ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•˜์ง€ ๋ชปํ•˜๋Š” Thread๋„ ์žˆ๊ณ , ํƒˆ์ถœํ•˜๋”๋ผ๋„ number์˜ ๊ฐ’์„ 0์œผ๋กœ ์ถœ๋ ฅํ•˜๋Š” Thread๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • number์™€ ready๊ฐ™์€ ๋ฐ์ดํ„ฐํ„ฐ ์Šคํ…Œ์ผ ๋ฐ์ดํ„ฐ(Stale Data)๋ผ๊ณ  ์œ„์™€ ๊ฐ™์€ ํ˜„์ƒ์„ ์Šคํ…Œ์ผ ํ˜„์ƒ ์ด๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.
  • ์Šคํ…Œ์ผ ํ˜„์ƒ์€ Multi Core Processor(ํ˜น์€ ๋‹ค์ค‘ CPU)์˜ ๊ตฌ์กฐ๋กœ๋ถ€ํ„ฐ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค..

Multi Core Processor์™€ Visibility

  • ์œ„ ๊ทธ๋ฆผ์—์„œ๋ณด๋ฉด ๊ฐ core๋Š” 1๊ฐœ ์ด์ƒ์˜ cache level์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ core๋Š” ์—ฐ์‚ฐ์„ ์œ„ํ•ด ๋งค๋ฒˆ Main Memory์— ์ง์ ‘ ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ  cache์— ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ๊ฐ core๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Thread cache์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด์„œ ์—ฐ์‚ฐ์„ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์‹ค์ œ๋กœ Main Memory์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ์™€ ๊ฐ Thread๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ๊ฐ€์‹œ์„ฑ ๋ฌธ์ œ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿคข ๐Ÿคข ๐Ÿคข
  • ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์‚ดํŽด๋ณด๋ฉด ๊ฐ ReaderThread์™€ Main Thread๊ฐ€ ๋‹ค๋ฅธ core์—์„œ ์—ฐ์‚ฐ๋  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์ด๋•Œ ๋™๊ธฐํ™”๊ฐ€ ์ด๋ค„์ง€์ง€ ์•Š๋Š”๋‹ค๋ฉด, Main Thread๊ฐ€ number๋‚˜ ready์˜ ๊ฐ’์„ ๋ฐ”๊พธ๋”๋ผ๋„, ๊ฐ ReaderTrehad์˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” core๋Š” ์ž์‹ ์˜ cache์— ์žˆ๋Š” ๊ฐ’์„ ๋ณด๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์งˆ์ˆ˜๋„ ์žˆ๊ณ  number์— ์ž…๋ ฅํ•œ ๊ฐ’์ด 0์œผ๋กœ ๋‚˜์˜ฌ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •๋ฆฌ

Instance Variable

  • JVM Runtime Data Area์˜ Heap์— ์ƒ์„ฑ๋œ Instance๋Š” ๋ชจ๋“  Thread์—์„œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๊ณต์œ  ์ž์›์›์ž…๋‹ˆ๋‹ค.
  • Instance๊ฐ€ ๋ฉ”์†Œ๋“œ๋งŒ ์ง€๋‹ˆ๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€๋Š” ๊ฐ Thread๋งŒ ์‚ฌ์šฉํ•˜๋Š” Stack์˜์—ญ์ด๋‹ˆ ๋ฌธ์ œ๊ฐ€ ์—†์„ ํ…Œ์ง€๋งŒ, ์ƒํƒœ๋ฅผ(Instance Variable)์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉด ์ด ์ƒํƒœ์—๋Š” ๋ชจ๋“  Thread๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋™๊ธฐํ™” ๋˜์ง€ ์•Š๋Š” ๊ฐ์ฒด์˜ ์ƒํƒœ์— ์—ฌ๋Ÿฌ Thread๊ฐ€ ์ ‘๊ทผํ•˜๋ฉด ๊ฒฝ์Ÿ์กฐ๊ฑด(race condition)์„ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด๋•Œ ํ•ด๋‹น ์ž์›์„ ํ†ตํ•œ ์—ฐ์‚ฐ์ด ์›์ž์„ฑ์„ ๋„์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ผ๊ด€์ ์ธ ์—ฐ์‚ฐ์˜ ๊ธฐ๋Œ€๊ฐ’์„ ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Class Variable

  • VM Runtime Data Area์˜ Method Area์— ํ• ๋‹น๋œ Class Variable์€ ๋ชจ๋“  Thread์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ณต์œ  ์ž์›์ž…๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ ๋™๊ธฐํ™”๊ฐ€ ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ํ•ด๋‹น ์ž์›์— ์—ฌ๋Ÿฌ Thread๊ฐ€ ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด Instance Variable์—์„œ ์ผ์–ด๋‚ฌ๋˜ ๋™์‹œ์„ฑ ์ด์Šˆ๋ฅผ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • Class Variable์ด๋‚˜ Instance Variable์—์„œ ๋‚˜ํƒ€๋‚ฌ๋˜ ๋™์‹œ์„ฑ ์ด์Šˆ๋Š” Synchronized ํ‚ค์›Œ๋“œ๋‚˜ Lock์„ ์‚ฌ์šฉํ•œ ๋™๊ธฐํ™”๋ฅผ ํ†ตํ•ด Thread Safety๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • Synchronization์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ์•„ํ‹ฐํด์„ ํ†ตํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Visibility

  • Multi Core Processor, Multi Threading ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐ core๋Š” ์ž์‹ ์˜ cache์— Main Memory์—์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ Thread์—์„œ ๋ณ€๊ฒฝํ•œ ๊ฐ’์ด Main Memory์— ์ฆ‰์‹œ ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ…Œ์ผ(stale)ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์ฆ‰, ๊ฐ core์—์„œ๋Š” ๋‹ค๋ฅธ core์˜ cache์— ์–ด๋–ค ๊ฐ’์ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  • volatile ํ‚ค์›Œ๋“œ๋ฅผ ๋ณ€์ˆ˜์— ๋ถ™์—ฌ์ฃผ๋ฉด ๊ฐ core์˜ ์—ฐ์‚ฐ๊ฒฐ๊ณผ๋ฅผ main memory์— flush ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(volatile ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ๋‹ค๋ฅธ ์•„ํ‹ฐํด์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค)
  • ๋‹ค๋งŒ ์ด๋•Œ ์›์ž์„ฑ์ด ์ง€์ผœ์ง€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ race condition์„ ๊ฐ€์ง€๊ฒŒ ๋˜์–ด ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ‘‰ ์ฐธ์กฐ
๋ฉ€ํ‹ฐ์ฝ”์–ด๋ฅผ 100% ํ™œ์šฉํ•˜๋Š” ์ž๋ฐ” ๋ณ‘๋ ฌํ”„๋กœ๊ทธ๋ž˜๋ฐ
Java Performance Fundamental
Guide to the Volatile Keyword in Java

0๊ฐœ์˜ ๋Œ“๊ธ€