ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Thread] Volatile์ด๋ž€, Volatile๊ณผ DCL(Double Checking Locking) ๊ณต๋ถ€ ๊ธฐ๋ก
    ๊ฐœ๋ฐœ/Java 2022. 4. 24. 00:02

    ๐Ÿ’กvolatile์€ ์–ธ์ œ ์‚ฌ์šฉํ• ๊นŒ?

    ์ž๋ฐ”์˜ ์˜ˆ์•ฝ์–ด ์ค‘์—๋Š” volatile๋ผ๋Š” ๊ฒƒ์ด ์žˆ๋‹ค. ์ด ์˜ˆ์•ฝ์–ด๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ์‹œ์—๋งŒ ์‚ฌ์šฉ๋œ๋‹ค.

    ์ด ์˜ˆ์•ฝ์–ด์— ๋Œ€ํ•œ ์„ค๋ช…์„ ๋“ฃ๊ธฐ ์ „์— ๋จผ์ € ๋‹ค์Œ์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž. (์ฝ”๋“œ ์„ค๋ช…์€ ์ฃผ์„์œผ๋กœ ๋Œ€์ฒดํ•œ๋‹ค.)

     

    VolatileSample.java

    package e.thread.volat;
    
    public class VolatileSample extends Thread{
    
        //instanceVariable์ด๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ ์žˆ๊ณ , ๊ธฐ๋ณธ ๊ฐ’์„ 0์œผ๋กœ ์ง€์ •ํ–ˆ๋‹ค.
        private double instanceVariable = 0; 
        
        //instanceVariable ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์„œ๋“œ
        void setDouble(double value) {
            this.instanceVariable = value;
        }
    
        public void run() {
          //instanceVariable ๊ฐ’์ด 0์ด๋ฉด ๊ณ„์† while ๋ฌธ์žฅ์„ ์‹คํ–‰ํ•œ๋‹ค.
          while (instanceVariable == 0); 
           
          //instanceVariable ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๊ณ , ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋Š” ์ž‘์—…์ด ์ข…๋ฃŒ๋œ๋‹ค.
          System.out.println(instanceVariable); 
          
        }
    }

     

    RunVolatile.java (main)

    package e.thread.volat;
    
    public class RunVolatile {
    
        public static void main(String[] args) {
            RunVolatile sample = new RunVolatile();
            sample.runVolatileSample();
        }
    
        public void runVolatileSample() {
            //sample์ด๋ผ๋Š” VolatileSample ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.
            VolatileSample sample = new VolatileSample();
            sample.start();
            
            //1์ดˆ๋ฅผ ๋Œ€๊ธฐํ•œ ํ›„
            try{
                Thread.sleep(1000);
            }catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Sleep ended !!!");
            
            //sample ๊ฐ์ฒด์— ์žˆ๋Š” instanceVariable ๊ฐ’์„ -1๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋๋‚ธ๋‹ค.
            sample.setDouble(-1);
            System.out.println("Set value is completed");
        }
    }

     

    ๊ฒฐ๊ณผ๋Š” ์–ด๋–ป๊ฒŒ ๋‚˜์˜ฌ๊นŒ?

    Sleep ended !!!
    Set value is completed !!!

     

    ๊ทธ๋ƒฅ ๋ณด๋ฉด ์ •์ƒ์ ์ธ ๊ฒƒ ๊ฐ™์ง€๋งŒ, sample์ด๋ผ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜์ง€ ์•Š๋Š”๋‹ค. sample.setDouble() ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋‹น์—ฐํžˆ instanceVariable ๊ฐ’์ด -1์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ๊ทธ๋žจ์ด ๋๋‚˜์•ผ๋งŒ ํ•œ๋‹ค. 

     

     

    ๐Ÿ’ก์™œ instanceVariable ๊ฐ’์€ ๋ฐ”๋€Œ์ง€ ์•Š๊ณ  while๋ฌธ์ด ๊ณ„์† ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ผ๊นŒ?

    ์ด ๋ฌธ์ œ์˜ ์›์ธ์€ "CPU ์บ์‹œ(cache)" ๋•Œ๋ฌธ์ด๋‹ค. ์ด ์˜ˆ์ œ์—์„œ ๋™์ผํ•œ sample์ด๋ผ๋Š” VolatileSample ํด๋ž˜์Šค์˜ ๊ฐ์ฒด์— ์žˆ๋Š” ๋ณ€์ˆ˜ ๊ฐ’์„ ๋ฐ”๊ฟจ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ์ด์ฒ˜๋Ÿผ ๊ฐ ์“ฐ๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฐธ์กฐํ•˜๊ฒŒ ๋  ๋•Œ์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์žฅ๋น„์˜ "๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ"์— ์ €์žฅ๋˜์ง€ ์•Š๊ณ , "CPU ์บ์‹œ"์— ์ €์žฅ๋˜๊ณ  ์ฐธ์กฐ๋œ๋‹ค. ๊ทธ๋ž˜์„œ, run() ๋ฉ”์†Œ๋“œ์˜ while๋ฌธ์—์„œ๋Š” "CPU ์บ์‹œ"์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” instanceVariable๋งŒ ์ณ๋‹ค ๋ณด๋ฉด์„œ "๋„ˆ ๊ณ„์† 0์ด์ง€? ๊ทธ๋Ÿผ ๊ณ„์† ๋ฐ˜๋ณตํ• ๊ฒŒ~~~" ํ•˜๋ฉด์„œ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•œ๋‹ค. 

     

    ์ด ์ƒํ™ฉ์—์„œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ setDouble() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ’์„ -1๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด, ์„œ๋กœ ๋‹ค๋ฅธ "CPU ์บ์‹œ"์— ์žˆ๋Š” instanceVariable ๊ฐ’์ด ๋ฐ”๋€๋‹ค. ๋”ฐ๋ผ์„œ, while๋ฌธ์—์„œ ์ฐธ์กฐํ•˜๋Š” "CPU ์บ์‹œ"์— ์žˆ๋Š” ๊ฐ’์€ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ณ„์† while๋ฌธ์ด ๋๋‚˜์ง€ ์•Š๊ณ  ์ง€์†๋˜๋Š” ๊ฒƒ์ด๋‹ค.

     

    ์ฆ‰, ์“ฐ๋ ˆ๋“œ์— ์„ ์–ธ๋œ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ผ์ด ์žˆ์„ ๋•Œ, ์•ž์„œ ๋งํ•œ volatile๋กœ ์„ ์–ธ์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ•ด๋‹น ๋ณ€์ˆ˜ ๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด "๋‚ด๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” volatile ๋ณ€์ˆ˜๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋Š”๋ฐ, ๋„ˆ๋„ ์ด๊ฑฐ ์“ฐ๋‹ˆ๊นŒ ๊ฐ’์„ ๋ฐ”๊ฟ”"๋ผ๊ณ  ์ด์•ผ๊ธฐํ•ด ์ค€๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ž๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์บ์‹œ๊ฐ€ ์•„๋‹Œ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐธ์กฐํ•˜๋„๋ก ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

    private volatile double instanceVariable = 0;

    ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ์ด์œ ๋Š” JIT ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ตœ์ ํ™” ์ž‘์—…(optimization)์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก instanceVariable์„ ์บ์‹œ์— ๋‘๊ณ  ์ตœ์ ํ™”๊ฐ€ ๋˜์–ด์„œ ์ด๋Ÿฌํ•œ ์ผ์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ฆ‰, Volatile ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค. ํ•ญ์ƒ volatile์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋งŒ์ผ ์ตœ์ ํ™”๊ฐ€ ๋˜์ง€ ์•Š์•„ ์บ์‹œ๊ฐ„์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’์„ ๋ณด์ง€ ์•Š์œผ๋ฉด volatile์„ ๊ตณ์ด ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. 

     

     

    ๐Ÿ’กvolatile๊ณผ DCL(Double Checking Locking)

    DCL(Double Checking Locking)์€ ThreadSafeํ•œ ์‹ฑ๊ธ€ํ†ค ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ๋ฐฉ์‹ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๊ธฐ์กด์˜ ๋ฉ”์†Œ๋“œ์— synchronized๋ฅผ ์„ ์–ธํ•œ ๋ฐฉ์‹์˜ ๋Œ€๊ธฐ์— ๋Œ€ํ•œ ์„ฑ๋Šฅ์ €ํ•˜์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•˜์—ฌ, ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ๋‹ค์Œ, ์ƒ์„ฑ๋˜์–ด ์žˆ์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ synchronizedํ•˜๋Š” ํŒจํ„ด์„ ๋งํ•œ๋‹ค.

     

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

     

    ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ, ๋‹ค์‹œ ํ•œ๋ฒˆ ํ™•์ธํ•ด ๋ณด์ž. ๋จผ์ € ์ž๋ฐ”4 ์ด์ „์˜ DCL๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ์ด๋‹ค.

    public class Singleton{
    
    	private static Singleton uniqueInstance;
    
    	private Singleton() {}
    
    	public static Singleton getInstance(){
    
    		if(uniqueInstance == null){
    			synchronized (Singleton.class){
    				if(uniqueInstance == null){
    					uniqueInstance = new Singleton();
    				}
    			}
    		}
    		return uniqueInstance;
    	}
    }

     

    ์ด์™€ ๊ฐ™์€ ํŒจํ„ด์—์„œ๋Š”, ๋งŒ์•ฝ Thread2๊ฐ€ ๊ฐ์ฒด ์ƒ์„ฑ ์ „์— ์ฒซ๋ฒˆ์งธ checking์— ์ง„์ž…ํ•˜์—ฌ๋„ synchronized์— ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.

    ์ด๋ฏธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์–ด์žˆ์„ ๊ฒฝ์šฐ synchronized์— ๊ฑธ๋ฆด๊ฒƒ ์—†์ด ๋ฐ”๋กœ ๊ฐ์ฒด๋ฅผ ๋ฐ›๊ฒŒ ๋œ๋‹ค.

     

    ํ•˜์ง€๋งŒ, new๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋ฅผ ์ฃผ์˜ํ•ด์„œ ์ƒ๊ฐํ•ด๋ณด์ž. ๊ฐ์ฒด ์ƒ์„ฑ์‹œ์—๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์˜ ํ™•๋ณด - ๋ณ€์ˆ˜์— ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„ ๋งํฌ - ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ์— ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ ์ˆœ์œผ๋กœ ์ž‘์—…์ด ์ด๋ฃจ์–ด์ง„๋‹ค. ์ด ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    1. Thread1์€ '๋ณ€์ˆ˜์— ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„ ๋งํฌ'๋งŒ ๋œ ์ƒํƒœ

    2. Thread2๊ฐ€ ์ฒซ๋ฒˆ์งธ if๋ฌธ์— ๊ฑธ๋ฆผ. ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๊ณ  ์ฐฉ๊ฐ

    3. Thread2๊ฐ€ getInstance()ํ•จ์ˆ˜๋ฅผ ํƒˆ์ถœ, ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„(์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„์ง ๋ฏธ์ƒ์„ฑ) ์œผ๋กœ ์ž‘์—…์„ ํ•˜๋ ค๊ณ  ํ•จ.

    4. ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ ๋ฐœ์ƒ

     

    ์ด๊ฒƒ์ด ์žฌ๋ฐฐ์น˜(reordering)๊ณผ์ •์— ์˜ํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

     

    ์ด๋•Œ ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ volatile์„ ์ ์šฉ์‹œํ‚ค๋ฉด, ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ/๋ฉ”์ธ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐฐ์น˜๊นŒ์ง€ ๋ฐ”๋กœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์–ด ์žฌ๋ฐฐ์น˜ ๋ฌธ์ œ๊ฐ€ ํ•ด์†Œ๋œ๋‹ค.

     

    public class Singleton{
    
    	private volatile static Singleton uniqueInstance;
    
    	private Singleton() {}
    
    	public static Singleton getInstance(){
    
    		if(uniqueInstance == null){
    			synchronized (Singleton.class){
    				if(uniqueInstance == null){
    					uniqueInstance = new Singleton();
    				}
    			}
    		}
    		return uniqueInstance;
    	}
    }

     

    ๐Ÿ“—Reference

    - ์ž๋ฐ”์˜ ์‹ 
    - https://yeahhappyday.tistory.com/entry/singleton-%ED%8C%A8%ED%84%B4%EA%B3%BC-volatileDCLDouble-Checking-Lockingttps://techvu.dev/87
    - https://bestugi.tistory.com/19

    ๋Œ“๊ธ€

Designed by Tistory.