๊ฐ์
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๊ณต์ ์์์ ์ฌ์ฉํ ๋, ์ฃผ๋ก ์์์ฑ๊ณผ ๊ฐ์์ฑ์ด ์ธ๊ธ๋๋๋ฐ ๊ฐ์์ฑ์ ๋ํด ์์ ๋ณด์!
๊ฐ์์ฑ (Visibility)
๊ฐ์์ฑ์ ์ฌ์ ์ ๋ฐ๋ฅด๋ฉด “๋์ ์ฝ๊ฒ ๋ณด์ด๋ ์ ๋”๋ฅผ ๋ปํ๋๋ฐ ์ปดํจํฐ๊ณผํ์์ ๊ฐ์์ฑ์ด๋ ๋ค์๊ณผ ๊ฐ์ ์๋ฏธ๋ฅผ ์ง๋๊ณ ์๋ค.
๊ฐ์์ฑ์ด๋ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ๊ฐ์ ์ค๋ ๋๊ฐ ๊ณต์ ์์์ ๋ํด์ ๋ชจ๋ ๊ฐ์ ์ํ๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๊ฒ์ ์๋ฏธํ๋ค.
๐ ํด๋น ์ ์๋ง์ผ๋ก๋ ์ง๊ด์ ์ธ ์ดํด๊ฐ ์ด๋ ค์ธ ์๋ ์๊ธฐ์ ์๋์ ์์ ์ฝ๋๋ฅผ ํตํด ์์ธํ๊ฒ ๋ค๋ค๋ณด์.
public class Main {
boolean runningFlag = true;
public void test() {
new Thread(()->{ // ์ฐ๋ ๋ ์์ฑ
int count = 0;
while (runningFlag) {
count++;
}
System.out.println("Thread 1 finished. Counted up to " + count);
}
).start();
new Thread(()-> { // ์ฐ๋ ๋ ์์ฑ
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Thread 2 finishing");
runningFlag = false;
}
).start();
}
public static void main(String[] args) throws InterruptedException {
new Main().test();
}
}
์์ ์ฝ๋๋ฅผ ๊ฐ๋ตํ๊ฒ ์ค๋ช ํ๋ฉด boolean ํ์ ๋ณ์์ธ runningFlag๋ฅผ true ๊ฐ์ผ๋ก ์ ์ธ ํ, 2๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ๋๋ฐ ์ฒซ ๋ฒ์งธ ์ค๋ ๋๋ runningFlag ๊ฐ์ ๋ฐ๋ฅธ while ๋ฐ๋ณต๋ฌธ์ผ๋ก int ํ์ ๋ณ์์ธ count๋ฅผ ์ฆ๊ฐ ์ฐ์ฐํ๋ ๊ฒ์ด๊ณ , ๋ ๋ฒ์งธ ์ค๋ ๋๋ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ 0.1์ด ํ์ runningFlag ๊ฐ์ false๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ด๋ค.
ํด๋น ์ฝ๋๋ฅผ ์คํํ๊ฒ ๋๋ฉด ์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ฒ ๋๋ค.
Thread 2 finishing
์์ํ๋ ๊ฒฐ๊ณผ๋ ๋ ๋ฒ์งธ ์ค๋ ๋๊ฐ ์คํ๋์ด ์ฒซ ๋ฒ์งธ ์ค๋ ๋์ ๋ฌดํ๋ฃจํ๊ฐ ์ข ๋ฃ๋๊ณ ๊ทธ๋์ ์ฆ๊ฐ์ฐ์ฐ๋ count ๋ณ์๋ฅผ ์ถ๋ ฅํ๋ ๊ฒ์ธ๋ฐ ์ฒซ ๋ฒ์งธ ์ค๋ ๋๊ฐ ์ข ๋ฃ๋์ง ์๋ ํ์์ด ๋ฐ์ํ๋ค.
ํด๋น ํ์์ด ๋ฐ์ํ ๊ทผ๋ณธ์ ์ธ ์์ธ์ ํ๋ CPU์ ๋ฉ๋ชจ๋ฆฌ ์ํคํ ์ฒ, ์ฆ ๋ ์ง์คํฐ์ ์บ์์ ์กด์ฌ ๋๋ฌธ์ด๋ค.
์์ ํ์์ ๋ํด ์์ธํ๊ฒ ์ค๋ช ํด๋ณด์๋ฉด ์์ฑํ ์ค๋ ๋๋ ๊ฐ๊ฐ์ CPU ์ฝ์ด์ ํ ๋น๋์ด ์์ ์ ์ฒ๋ฆฌํ๊ฒ ๋๋๋ฐ CPU ์ฝ์ด๋ง๋ค ์บ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์กด์ฌํ๋ค.
์ฒซ ๋ฒ์งธ ์ค๋ ๋๋ runningFlag ๋ณ์์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋, ์์ ์๊ฒ ํ ๋น๋ CPU ์ฝ์ด์ ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ฌ ๊ฐ์ ธ์ค๊ฒ ๋๊ณ , ๋ ๋ฒ์งธ ์ค๋ ๋ ๋ํ ์์ ์๊ฒ ํ ๋น๋ CPU ์ฝ์ด์ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ์๋ ๊ฐ์ ๋ณ๊ฒฝํ๊ณ ์ค๋ ๋๊ฐ ์ข ๋ฃ๋๋ฉด์ ๋ณ๊ฒฝ๋ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ์ ๋ฐ์ดํธํ๋ค.
๋ฉ๋ชจ๋ฆฌ์ ์๋ runningFlag ๋ณ์์ ๊ฐ์ด ๋ณ๊ฒฝ๋์์์๋ ๋ถ๊ตฌํ๊ณ ์ฒซ ๋ฒ์งธ ์ค๋ ๋๋ ๊ณ์ ์์ ์ ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐธ์กฐํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ค๋ ๋๊ฐ ์ข ๋ฃ๋์ง ์๋ ๊ฒ์ด๋ค.
์ ๊ทธ๋ฆผ์ฒ๋ผ ๊ฐ๊ฐ์ ์ค๋ ๋๊ฐ ๊ณต์ ํ๋ runningFlag ๋ณ์์ ๊ฐ์ ๋ํด ์๋ก ๋ณด์ฌ์ง๋ ๊ฐ์ด ๋ค๋ฅด๋ฏ๋ก ์ด๋ฅผ “๋น๊ฐ์์ฑ”์ด๋ผ๊ณ ํ๋ค.
โ [์ถ๊ฐ ๋ด์ฉ] ์บ์ ๋ฉ๋ชจ๋ฆฌ
๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์์ ๋ฐ์ดํฐ๋ฅผ Read/Write ํ๋ ค๋ฉด CPU๋ ์๋ฐฑ ์ฌ์ดํด์ ๋น์ฉ์ด ๋ค๊ธฐ ๋๋ฌธ์ ํ๋์ CPU๋ ์ฑ๋ฅ ํฅ์์ ์ํด CPU ๋ด์ ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
์บ์ ๋ฉ๋ชจ๋ฆฌ๋ CPU ์ฝ์ด๋ง๋ค ๊ฐ๊ฐ ๊ฐ์ง๊ณ ์๋ L1, L2 ์บ์์ ๋ชจ๋ CPU๊ฐ ๊ณต์ ํ๋ L3 ์บ์๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
CPU๋ ๋ฉ๋ชจ๋ฆฌ์์ ์ฝ์ด์จ ๋ฐ์ดํฐ๋ฅผ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๊ณ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ ์ง์คํฐ๋ก ๊ฐ์ ธ์์ ์ฒ๋ฆฌํ๋ค.
๋ฐ๋ผ์, ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋๋ ์บ์ ๋ฉ๋ชจ๋ฆฌ์ ํด๋น ๋ฐ์ดํฐ๊ฐ ์๋์ง ํ์ธํ๊ณ ์๋ ๊ฒฝ์ฐ์๋ง ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ์ ๊ทผํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฎ์ผ๋ก์จ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์๋ ๊ฒ์ด๋ค.
volatile ํค์๋
์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ฐ ์ธ์ด์์๋ "volatile" ํค์๋๋ฅผ ์ ๊ณตํ๋ค.
volatile ํค์๋๊ฐ ๋ถ์ ๋ณ์๋ ๊ฐ์ ์ฝ๊ฑฐ๋ ์ฐ๊ณ ์ ํ ๋, ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ์ง์ ์ ๊ทผํ๊ฒ ๋๋ค.
๋ฐ๋ผ์, ์์ runningFlag ๋ณ์์ volatile ํค์๋๋ฅผ ๋ถ์ฌ์ฃผ๋ฉด ์ฒซ ๋ฒ์งธ ์ค๋ ๋๊ฐ ์ ์ ์ข ๋ฃ๋จ์ ํ์ธํ ์ ์๋ค.
public class Main {
volatile boolean runningFlag = true;
...
...
}
๋ง์ง๋ง์ผ๋ก ์์๋ก ๋ ์ฝ๋๋ ๋ ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ์ฌ ํ ๊ฐ์ ์ค๋ ๋๋ง ๊ณต์ ์์์ ๋ํด Write ํ๋ ์ํฉ์ธ๋ฐ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ๊ณต์ ์์์ Write ํ๊ฒ ๋๋ค๋ฉด volatile ํค์๋๋ง์ผ๋ก๋ ๊ฒฝ์ ์ํ (Race Condition)์ ํด๊ฒฐํ ์ ์๊ธฐ ๋๋ฌธ์ synchronized ํค์๋๋ฅผ ์ฌ์ฉํด์ ์์์ฑ (Atomicity)์ ๋ณด์ฅํด์ผ ํ๋ค.
์์์ฑ์ด ์ด๋ค ๊ฒ์ธ์ง์ ๋ํด์๋ ๋ค์ ๊ธ์์ ๋ค๋ฃฐ ์์ ์ด๋ค.
โ [์ถ๊ฐ ๋ด์ฉ] volatile ํค์๋ in Java
Java์์ ์ง์ํ๋ “volatile” ํค์๋๋ ๋ค์๊ณผ ๊ฐ์ ํน์ฑ์ ๊ฐ์ง๋ค.
โ volatile๋ก ์ ์ธ๋ ๋ณ์๊ฐ ์๋ ์ฝ๋๋ ์ต์ ํ๋์ง ์๋๋ค.
โก volatile ํค์๋๋ ๋ณ์๋ฅผ 'Main Memory์ ์ ์ฅํ๊ฒ ๋ค'๋ผ๊ณ ๋ช ์ํ๋ ๊ฒ์ด๋ค.
โข volatile ํค์๋๊ฐ ๋ถ์ ๋ณ์๋ ๊ฐ์ Readํ๊ฑฐ๋ Write ํ ๋, ์บ์๋ฅผ ์ด์ฉํ์ง ์๊ณ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ์ง์ ์ ๊ทผํ์ฌ Read/Write๋ฅผ ํ๊ฒ ๋๋ค.
โ [์ถ๊ฐ ๋ด์ฉ] Full Visibility of Volatile Keyword in Java
Java์์์ volatile ํค์๋๋ volatile์ด ๋ถ์ ๋ณ์๋ง์ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋กํ๋ ๊ฒ์ด ์๋๋ผ, ํด๋น volatile ๋ณ์์ ํจ๊ป ๋ณด์ฌ์ง๋ ๋ชจ๋ ๋ณ์๊ฐ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋ก๋๋ค.
๐ ์ฆ, volatile ํค์๋๊ฐ ๋ถ์ ๋ณ์์ ํจ๊ป ๋ณด์ฌ์ง๋ ๋ชจ๋ ๋ณ์๊ฐ ๊ฐ์์ฑ ๋ณด์ฅ์ด ๋๋ค๋ ๊ฒ (Full Visibility)
๊ฐ๋จํ๊ฒ ์์ฝํ์๋ฉด ์๋์ ๊ฐ์ด ์ ๋ฆฌํ ์ ์๋ค.
โ Thread A๊ฐ volatile ๋ณ์์ Write ํ๋ ๊ฒฝ์ฐ, volatile ๋ณ์ ์ธ์๋ Thread A๊ฐ ๋ณผ ์ ์๋ ๋ชจ๋ ๋ณ์๋ค์ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ํจ๊ป ๊ธฐ๋ก๋๊ณ Thread B๋ ๊ทธ ์ต์ ๊ฐ์ ๋ณผ ์ ์๋ค.
โก Thread A๊ฐ volatile ๋ณ์๋ฅผ Read ํ๋ ๊ฒฝ์ฐ, Thread A์ ํ์๋๋ ๋ชจ๋ ๋ณ์๋ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์์ ๋ค์ ์ฝํ๋ค.
์ง๊ธ๊น์ง์ ์ค๋ช ์ผ๋ก ์ด๋์ ๋ ๊ฐ์ ์ก์๊ฒ ์ง๋ง, ์์ ์ฝ๋๋ฅผ ํตํด ์ด๋ป๊ฒ ์๋๋๋์ง ํ์ ํด๋ณด์.
public class YMD {
private int years;
private int months;
private volatile int days;
public void update(int years, int months, int days) {
this.years = years;
this.months = months;
this.days = days;
}
public int totalDays() {
int total = this.days;
total += months * 30;
total += years * 365;
return total;
}
}
์์ YMD ํด๋์ค์๋ years (์ฐ๋), months (๋ฌ), days (์ผ)์ 3๊ฐ์ง ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์๊ณ ๊ทธ ์ค days ๋ณ์๋ง volatile ํค์๋๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค.
update() ๋ฉ์๋ ํธ์ถ ์, days ๋ณ์์ ๊ฐ์ ์ฐ๊ฒ ๋๋ฉด (Write), ํด๋น ์ค๋ ๋์์ ๋ณผ ์ ์๋ ๋ชจ๋ ๋ณ์๋ค ๋ํ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋ก๋๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
๐ Full Visibilty๋ฅผ ๋ง์กฑ์ํค๊ธฐ ์ํด ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ Write ํ๊ฒ ๋๋ ๊ฒฝ์ฐ์๋ volatile ๋ณ์๋ฅผ ๋ง์ง๋ง์ Write ํด์ฃผ์ด์ผ ํ๋ค.
์ฆ, volatile ํค์๋๊ฐ ๋ถ์ง ์์ years, months ๋ณ์๋ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋ก๋์ด ๊ฐ์์ฑ ๋ณด์ฅ์ด ๋๋ค๋ ๊ฒ์ด๋ค. (Full Visibility)
totalDay() ๋ฉ์๋ ํธ์ถ ์์๋ days ๋ณ์๋ฅผ ์ฝ์ด์ค๋ฉด์ years, months ๊ฐ๋ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์์ ์ฝ์ด์จ๋ค.
๐ ๋ง์ฐฌ๊ฐ์ง๋ก Full Visibility๋ฅผ ๋ง์กฑ์ํค๊ธฐ ์ํด ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ Read ํ๊ฒ ๋๋ ๊ฒฝ์ฐ๋ volatile ๋ณ์๋ฅผ ๋งจ ์ฒ์์ Read ํด์ฃผ์ด์ผ ํ๋ค.
โ [์ถ๊ฐ ๋ด์ฉ] ๋ช ๋ น์ด ์ฌ์ ๋ ฌ์ผ๋ก ๋ฐ์ํ๋ ๋ฌธ์ (Instruction Reordering Challenges)
JVM (์ปดํ์ผ๋ฌ)์์๋ ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด ์ฝ๋์ ์คํ ๋์์ ๋ฐ๊พธ์ง ์๋ ์ ์์ ํ๋ก๊ทธ๋จ์ ๋ช ๋ น์ด ์์๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
(Before)
int a = 1;
int b = 2;
a++;
b++;
(After)
int a = 1;
a++;
int b = 2;
b++;
๋ค๋ง, ๋ช ๋ น์ด Reordering ํ๋ ๊ณผ์ ์ volatile ๋ณ์๊ฐ ํฌํจ๋๋ฉด ์๋์ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
(Before)
public class YMD {
private int years;
private int months;
private volatile int days;
public void update(int years, int months, int days) {
this.years = years;
this.months = months;
this.days = days; // Full Visibility๋ฅผ ๋ง์กฑ์ํค๊ธฐ ์ํด volatile ๋ณ์๋ ๋ง์ง๋ง์ Write
}
(After)
...
public void update(int years, int months, int days) {
this.days = days;
this.months = months;
this.years = years;
}
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ช ๋ น์ด Reordering ํ๊ฒ ๋ ํ์๋ months, years ๋ณ์๊ฐ ๊ฐ์ ์ ์ฅํ๊ธฐ ์ ์ volatile ๋ณ์์ธ days๊ฐ ๋จผ์ ๊ฐ์ ์ ์ฅํ๋ฏ๋ก months, year ๋ณ์๋ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋์ง ์๋๋ค. → ์ฆ, Full Visibility ํ์ง ๋ชปํ๋ค.
์ด๋ ๊ฒ volatile์ ์ฌ์ฉํ๋ฉด Reordering ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด, ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋ฐ์ volatile์ happens befored์ ๋ณด์ฅํ๋ค.
“happens befored”์ด๋ JVM์์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ ๋ ฌํ๋ ๊ฒฝ์ฐ, volatile ๋ณ์์ ๋ํ ์ฐ๊ธฐ ๋ช ๋ น ์ด์ ์ ๋ช ๋ น๋ค์ ์ฌ์ ๋ ฌ ์ดํ์๋ volatile ๋ณ์์ ๋ํ ์ฐ๊ธฐ ๋ช ๋ น ์ด์ ์ ์คํ๋๋๋ก ์ ์งํ๋ค.
volatile ๋ณ์์ ๋ํ ์ฝ๊ธฐ ๋ช ๋ น ์ดํ์ ๋ช ๋ น๋ค์ ์ฌ์ ๋ ฌ ์ดํ์๋ volatile ๋ณ์์ ๋ํ ์ฝ๊ธฐ ๋ช ๋ น ์ดํ์ ์คํ๋๋๋ก ์ ์งํ๋ค.
์ฆ, ๊ฐ๋จํ๊ฒ ๋งํด์ ๋ช ๋ น์ด ์ฌ์ ๋ ฌ์ด ๋ฐ์ํ์ง ์๋ ๊ฒ์ด๋ค!!
Reference
https://yeonyeon.tistory.com/270
https://onlyfor-me-blog.tistory.com/539
https://ko.wikipedia.org/wiki/%EC%9B%90%EC%9E%90%EC%84%B1
https://ttl-blog.tistory.com/238#%F0%9F%A7%90%20volatile%EC%9D%98%20%EB%AC%B8%EC%A0%9C-1
https://mygumi.tistory.com/111
http://tutorials.jenkov.com/java-concurrency/volatile.html
'๐ ์ฐ์ฌ ์๋ฆฌ์ฆ > ์ฃผ๋์ด ๊ฐ๋ฐ์๊ฐ ์๋ฉด ์ข์ ๋ด์ฉ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Git ์์ฃผ ์ฐ์ด๋ ๋ช ๋ น์ด ๋ชจ์ (0) | 2023.07.28 |
---|---|
๋ฉํฐ ์ค๋ ๋ - ์์์ฑ (Atomicity) (0) | 2023.05.03 |
๋์์ฑ (Concurrency) ๋ฐ ๋ณ๋ ฌ์ฑ (Parallelism) (0) | 2023.05.02 |
์ฝ๋ ์ปจ๋ฒค์ (Code Convention) (2) | 2023.03.08 |
๊ตฌ๋ฌธ ์๋ฌ, ๋ ผ๋ฆฌ ์๋ฌ, ๋ฐํ์ ์๋ฌ (0) | 2023.02.13 |