-
[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'๊ฐ๋ฐ > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ