Item 78. Mutable Data Sharing
๊ณต์ ์ค์ธ ๊ฐ๋ณ ๋ฐ์ดํฐ๋ ๋๊ธฐํํด ์ฌ์ฉํ๋ผ
synchronized
ํค์๋๋ ํด๋น ๋ฉ์๋๋ ๋ธ๋ก์ ํ ๋ฒ์ ํ ์ค๋ ๋์ฉ ์ํํ๋๋ก ๋ณด์ฅํ๋ฉฐ, ์๋์ ํน์ง์ ๊ฐ์ง๋ค.
ํ ๊ฐ์ฒด๊ฐ ์ผ๊ด๋ ์ํ๋ฅผ ๊ฐ์ง๊ณ ์์ฑ๋์์ ๋, ํด๋น ๊ฐ์ฒด์ ์ ๊ทผํ๋ ๋ฉ์๋๋ ํด๋น ๊ฐ์ฒด์ด Lock์ ํ๋
Lock์ ํ๋ํ ๋ฉ์๋๋ ๊ฐ์ฒด์ ์ํ๋ฅผ ํ์ธํ๊ฑฐ๋ ๋ณ๊ฒฝํ ์ ์์
๋ฉ์๋ ์คํ์ด ์ข ๋ฃ๋๋ฉด Lock์ ํด์
๋๊ธฐํ ์์ด๋ ํ ์ค๋ ๋๊ฐ ๊ฐ์ฒด์ ์ผ๊ด์ฑ์ด ๊นจ์ง ์ํ๋ฅผ ๋ณด๊ฒ ๋ ์ ์์
๋๊ธฐํ๋ ๋ฉ์๋๋ ๋ธ๋ก์ ๋ค์ด๊ฐ ์ค๋ ๋๊ฐ ๊ฐ์ฒด์ ์ผ๊ด์ฑ์ด ๊นจ์ง ์ํ๋ฅผ ๋ณด์ง ๋ชปํ๋๋ก ๋ณด์ฅ
Java์์ ๊ฐ๋ณ ๋ฐ์ดํฐ ์ค๋ ๋๊ฐ ํต์
์๋ ์ฝ๋๋ boolean ํ๋๋ฅผ ๊ฒ์ฌํ๋ฉด์ ๊ทธ ๊ฐ์ด true๊ฐ ์๋๋ฉด ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ฉฐ ๊ฐ์ ์ฆ๊ฐ์ํค๋ ์ฝ๋์ด๋ค.
class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested) {
i++;
System.out.println(i);
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
1์ด ํ ๋ฉ์ธ ์ค๋ ๋์์ stopRequested ํ๋์ ๊ฐ์ true๋ก ๋ณ๊ฒฝํ๊ณ ์์ง๋ง, ์ค์ ๋ก ๋ณ๊ฒฝ๋ ๊ฐ์ ๋ฐ๋ก ์ฝ์ง ๋ชปํ๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ ์ ์๋ค. ** ์คํ ํ๊ฒฝ์ ๋ฐ๋ผ 1์ด ํ์ ๋ฐ๋ก ์ข ๋ฃ๋ ์๋ ์๋ค.
synchronized ๋ฉ์๋๋ฅผ ์ด์ฉํ ๋๊ธฐํ
ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ stopRequested ํ๋์ ์ ๊ทผํ๋ ๋ฉ์๋๋ฅผ ๋๊ธฐํ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested()) {
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
์ฐ๊ธฐ(requestStop
)์ ์ฝ๊ธฐ(stopRequested
) ๋ฉ์๋ ๋ชจ๋ synchronized
ํค์๋๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ,
์ฝ๊ธฐ์ ์ฐ๊ธฐ ์ ๋ถ synchronized
ํค์๋๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ๋๊ธฐํ๊ฐ ์ ๋๋ก ์ด๋ฃจ์ด์ง์ง ์๋๋ค.(๊ฐํน ์ ๋์ํ๋ ๊ฒ ์ฒ๋ผ ๋ณด์ผ ์ ์์ง๋ง ์ค์ ๋ก ๊ทธ๋ ์ง ์๋ค.)
volatile ํ๋๋ฅผ ์ด์ฉํ ๋๊ธฐํ
volatile
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ํ๋๋ฅผ ์ฝ๊ณ ์ฐ๋ ๋์์ด ํญ์ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์๋๋๋ก ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
class StopThread {
private static volatile boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested) {
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
volatile ์ฃผ์์ฌํญ
์์ ๋ฌธ์ ๋ volatile
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ง๋ง, ํด๋น ํค์๋๋ ํ๋๋ฅผ ์ฝ๊ณ ์ฐ๋ ํต์ ๋ง ๋ณด์ฅํ๋ฉฐ, ๋์์ฑ์ ๋ณด์ฅํ์ง๋ ์๋๋ค.
class AddTest {
private static volatile int count = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
count++;
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
count++;
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count); // 1592872
}
}
์ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด 2000000์ด ๋์์ผ ํ ๊ฒ ๊ฐ์ง๋ง, ์ค์ ๋ก๋ 1592872(2000000์ด ์๋ ๊ฐ)๊ฐ ๋์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด๋ volatile
ํค์๋๋ ํด๋น ํ๋๋ฅผ ์ฝ๊ณ ์ฐ๋ ํต์ ๋ง ๋ณด์ฅํ๋ฉฐ, ๋์์ฑ์ ๋ณด์ฅํ์ง๋ ์๊ธฐ ๋๋ฌธ์ด๋ค.
synchronized ๋ธ๋ก์ ์ด์ฉํ ๋๊ธฐํ
์ฒ์ ๋์๋ synchronized
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ํ๋๋ฅผ ์ฝ๊ณ ์ฐ๋ ํต์ ๊ณผ ๋์์ฑ์ ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
class AddTest {
private static int count = 0;
private static synchronized void add() {
count++;
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
add();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
add();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
Atomic ํด๋์ค๋ฅผ ์ด์ฉํ ๋๊ธฐํ
๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์ ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ๋ณ๋์ synchronized ํค์๋ ์์ด ํด๊ฒฐํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก java.util.concurrent.atomic
ํจํค์ง์ ์๋ Atomic ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
(๋ด๋ถ์ ์ผ๋ก volatile ํค์๋์ CAS ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์๋ค.)
import java.util.concurrent.atomic.AtomicInteger;
class AddTest {
private static final AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
count.incrementAndGet();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000000; i++) {
count.incrementAndGet();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count.get());
}
}
๊ฒฐ๋ก
๊ฐ๋ณ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์์ง๋ง, ๋ ๋ณต์กํ ๋ก์ง์์๋ ๋ฌธ์ ๊ฐ ์ด๋์ ๋ฐ์ํ ์ง ์์ธกํ ์ ์์ผ๋ฏ๋ก ๊ฐ๋ณ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ์ง ์๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข๋ค. ๋ง์ฝ ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ๋ณ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํด์ผ ํ๋ค๋ฉด ์๋ ์ฌํญ์ ์ฃผ์ํ์.
ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๋ ๋ฉ์๋ ์ ๋ถ
synchronized
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ธฐํvolatile
ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํต์ ์ ๋ณด์ฅ๋์ง๋ง, ๋์์ฑ์ ๋ณด์ฅ๋์ง ์๋ ๊ฒ์ ์ฃผ์๊ฐ๋ณ ๋ฐ์ดํฐ๊ฐ
java.util.concurrent.atomic
ํจํค์ง์์ ์ ๊ณตํ๋ค๋ฉด ํด๋น ํด๋์ค๋ฅผ ๊ณ ๋ คํด๋ ์ข์
Last updated
Was this helpful?