๐ฏ ์์ดํ 79. ๊ณผ๋ํ ๋๊ธฐํ๋ ํผํ๋ผ.
์๋ต ๋ถ๊ฐ์ ์์ ์คํจ๋ฅผ ํผํ๋ ค๋ฉด ๋๊ธฐํ ๋ฉ์๋๋ ๋๊ธฐํ ๋ธ๋ก ์์์๋ ์ ์ด๋ฅผ ์ ๋๋ก ํด๋ผ์ด์ธํธ์ ์๋ํ๋ฉด ์๋๋ค. ๋๊ธฐํ๋ ์์ญ์ ํฌํจํ ํด๋์ค ๊ด์ ์์๋ ์ด๋ฐ ๋ฉ์๋๋ ๋ชจ๋ ๋ฐ๊นฅ ์ธ์์์ ์จ ์ธ๊ณ์ธ์ด๋ฏ๋ก ์์ธกํ ์ ์๋ ์ด์๋ฅผ ๋ฐ์ ์ํจ๋ค
- ์๋ชป๋ ์ฝ๋. ๋๊ธฐํ ๋ธ๋ก ์์์ ์ธ๊ณ์ธ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
public class ObservableSet<E> extends ForwardingSet<E> {
public ObservableSet(Set<E> set) { super(set); }
private final List<SetObserver<E>> observers = new ArrayList<>();
public void addObserver(SetObserver<E> observer) {
synchronized(observers) {
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer) {
synchronized(observers) {
return observers.remove(observer);
}
}
private void notifyElementAdded(E element) {
synchronized(observers) {
for (SetObserver<E> observer : observers)
observer.added(this, element);
}
}
@Override
public boolean add(E element) {
boolean added = super.add(element);
if (added)
notifyElementAdded(element);
return added;
}
}
public static void main(String[] args) {
ObservableSet<Integer> set = new ObservableSet<>(new HashSet<>());
set.addObserver(new SetObserver<>() {
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if (e == 23) // ๊ฐ์ด 23์ด๋ฉด ์์ ์ ๊ตฌ๋
ํด์งํ๋ค.
s.removeObserver(this);
}
});
for (int i = 0; i < 100; i++)
set.add(i);
}
์ด ํ๋ก๊ทธ๋จ์ 23๊น์ง ์ถ๋ ฅํ ๋ค์ ConcurrentModificationException
์ ๋์ง๋ค. added
๋ฉ์๋ ํธ์ถ์ด ์ผ์ด๋ ์์ ์ด notifyElementAdded
๊ฐ ๊ด์ฐฐ์๋ค์ ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ ๋์ค์ด๊ธฐ ๋๋ฌธ์ด๋ค.
- ์ธ๋ฐ์์ด ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ ๊ด์ฐฐ์
public static void main(String[] args) {
ObservableSet<Integer> set = new ObservableSet<>(new HashSet<>());
set.addObserver(new SetObserver<>() {
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if (e == 23) {
ExecutorService exec = Executors.newSingleThreadExecutor();
try {
exec.submit(() -> s.removeObserver(this)).get();
} catch (ExecutionException | InterruptedException ex) {
throw new AssertionError(ex);
} finally {
exec.shutdown();
}
}
}
});
for (int i = 0; i < 100; i++)
set.add(i);
}
์ด ํ๋ก๊ทธ๋จ์ ์คํํ๋ฉด ์์ธ๋ ๋์ง ์์ง๋ง ๊ต์ฐฉ์ํ์ ๋น ์ง๋ค.
- ํด๊ฒฐ์ฑ 1 ์ธ๊ณ์ธ ๋ฉ์๋ ํธ์ถ์ ๋๊ธฐํ ๋ธ๋ก ๋ฐ๊นฅ์ผ๋ก ์ฎ๊ธด๋ค.
private void notifyElementAdded(E element) {
List<SetObserver<E>> snapshot = null;
synchronized(observers) {
snapshot = new ArrayList<>(observers);
}
for (SetObserver<E> observer : snapshot)
observer.added(this, element);
}
- ํด๊ฒฐ์ฑ
2
CopyOnWriteArrayList
๋ฅผ ์ฌ์ฉํด ๊ตฌํํ ์ค๋ ๋ ์์ ํ๊ณ ๊ด์ฐฐ ๊ฐ๋ฅํ ์งํฉ
private final List<SetObserver<E>> observers = new CopyOnWriteArrayList<>();
๊ธฐ๋ณธ ๊ท์น์ ๋๊ธฐํ ์์ญ์์๋ ๊ฐ๋ฅํ ํ ์ผ์ ์ ๊ฒ ํ๋ ๊ฒ์ด๋ค.
- ๊ฐ๋ณ ํด๋์ค๋ฅผ ์์ฑํ๋ ค๊ฑฐ๋ ๋ค์ ๋ ์ ํ์ง ์ค ํ๋๋ฅผ ๋ฐ๋ฅด์.
1.๋๊ธฐํ๋ฅผ ํ์ง๋ง๊ณ , ํด๋์ค๋ฅผ ๋์์ ์ฌ์ฉํด์ผ ํ๋ ํด๋์ค๊ฐ ์ธ๋ถ์์ ๋๊ธฐํ๋๋ก ํ์.
2.๋๊ธฐํ๋ฅผ ๋ด๋ถ์์ ์ํํด ์ค๋ ๋ ์์ ํ ํด๋์ค๋ก ๋ง๋ค์.
1๏ธโฃ ๋ฝ ๋ถํ (lock splitting)
2๏ธโฃ ๋ฝ ์คํธ๋ผ์ด์ดํ(lock striping)
3๏ธโฃ ๋น์ฐจ๋จ ๋์์ฑ ์ ์ด(nonblocking concurrency control)
์ฐธ๊ณ ์๋ฃ
Joshua Bloch, ใEffective Java 3/Eใ, ๊ฐ์๋งต์ ์ฎ๊น, ํ๋ก๊ทธ๋๋ฐ์ธ์ฌ์ดํธ(2018)
http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262281&orderClick=LEa&Kc=