2023. 1. 21. 19:14ใJAVA/Effective JAVA
item07. ๋ค ์ด ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
์๋ฐ์์๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋๋ถ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ C๋ C++์ ๋นํด์๋ ํธํ๋ค๊ณ ํ ์ ์์ง๋ง ๊ทธ๋ ๋ค๊ณ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์์ ์ ๊ฒฝ์ฐ์ง ์์๋ ๋๋ ๊ฒ์ ์๋๋ค.
๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ํด๋์ค๊ฐ ์๋ค๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์ผ์ด๋ ์ ์๊ณ , ์ด ๋ฉ๋ชจ๋ฆฌ ๋์๋ ๊ฒ์ผ๋ก๋ ์ ๋๋ฌ๋์ง ์๊ธฐ ๋๋ฌธ์ ์์คํ ์ ์๋ ๊ฐ ์ ๋ณตํด ์๋ค๊ฐ.. ์ฌํ ๊ฒฝ์ฐ์๋ ๋์คํฌ ํ์ด์ง์ด๋ OutoutMemoryError๋ฅผ ์ผ์ผ์ผ์ ํ๋ก๊ทธ๋จ์ด ์๊ธฐ์น ์๊ฒ ์ข ๋ฃ๋ ์๋ ์๋ค..
๊ทธ๋ฌ๋ฏ๋ก ์ด๋ค ๊ฒฝ์ฐ์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฉฐ, ํด๊ฒฐ? ๋ฐฉ๋ฒ์ ๋ฌด์์ธ์ง์ ๋ํด์ item07์์ ์๊ฐํ๊ณ ์๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ ๐พ
: ์ด๋ค ๊ฐ์ฒด์ ๋ํ ๋ ํผ๋ฐ์ค๊ฐ ๋จ์์๋ค๋ฉด ํด๋น ๊ฐ์ฒด๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ๋์์ด ๋์ง ์๋๋ค.
- stack
package chapter01.item07.stack;
import java.util.Arrays;
import java.util.EmptyStackException;
/**
* item07. ๋ค ์ด ๊ฐ์ฒด์ ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
*/
public class Stack
{
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e)
{
ensureCapacity();
elements[size++] = e;
}
// ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์กด์ฌํ๋ ์ฝ๋
public Object pop()
{
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
}
/**
* ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ํ๋ณดํ๋ค.
* ๋ฐฐ์ด ํฌ๊ธฐ๋ฅผ ๋๋ ค์ผ ํ ๋๋ง๋ค ๋๋ต 2๋ฐฐ์ฉ ๋๋ฆฐ๋ค.
*/
private void ensureCapacity()
{
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
public static void main(String[] args)
{
Stack stack = new Stack();
for (String arg : args)
{
stack.push(arg);
}
while (true)
{
System.out.println("stack.pop() = " + stack.pop());
}
}
}
์ดํํฐ๋ธ ์๋ฐ์์ ์์ ๋ก ์ ๊ณตํ Stack ์ํ ์ฝ๋์ธ๋ฐ ์ด ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ฌธ์ ๊ฐ ์์ด๋ณด์ธ๋ค..
์ค์ ๋ก๋ ๊ฐ์ข ํ ์คํธ๋ฅผ ๋ค ํ๋๋ผ๋ ๋ฌธ์ ๊ฐ ์๋ค.
ํ์ง๋ง '๋ฉ๋ชจ๋ฆฌ ๋์'๋ผ๋ ๋ฌธ์ ๊ฐ ์กด์ฌํ๋ค.
์ด ์ฝ๋๋ฅผ ๋ณด๋ฉด ์คํ์ด ์ปค์ก๋ค๊ฐ ์ค์ด๋ค์์ ๋ ์คํ์์ ๊บผ๋ด์ง ๊ฐ์ฒด๋ค์ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ํ์ํ์ง ์๋๋ค!
๊ฐ์ฒด๋ค์ ๋ ์ด์ ์ฌ์ฉํ์ง ์๋๋ฐ๋ ํ์ํ์ง ์๋๋ค.
์๋ํ๋ฉด Stack์ด ๊ฐ์ฒด๋ค์ ๋ค ์ด ์ฐธ์กฐ๋ฅผ ์ฌ์ ํ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฐ๋น์ง ์ปฌ๋ ์ ์์๋ ๊ฐ์ฒด ์ฐธ์กฐ ํ๋๋ฅผ ์ด๋ ค๋๋ฉด ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ ๊ทธ ๊ฐ์ฒด๋ฟ๋ง ์๋๋ผ ๊ทธ ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ํ์ํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ์ ์ฌ์ ์ผ๋ก๋ ์ฑ๋ฅ์ ์ ์ํฅ์ ๋ผ์น ์ ์๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ1) ํด๋น ์ฐธ์กฐ๋ฅผ ๋ค ์ผ์ ๋ null ์ฒ๋ฆฌ (์ฐธ์กฐ ํด์ ) ํ๋ฉด ๋๋ค.
package chapter01.item07.stack;
import java.util.Arrays;
import java.util.EmptyStackException;
/**
* item07. ๋ค ์ด ๊ฐ์ฒด์ ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
*/
public class Stack
{
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e)
{
ensureCapacity();
elements[size++] = e;
}
// ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์กด์ฌํ๋ ์ฝ๋
// public Object pop()
// {
// if (size == 0) {
// throw new EmptyStackException();
// }
// return elements[--size];
// }
/**
* ์์๋ฅผ ์ํ ๊ณต๊ฐ์ ์ ์ด๋ ํ๋ ์ด์ ํ๋ณดํ๋ค.
* ๋ฐฐ์ด ํฌ๊ธฐ๋ฅผ ๋๋ ค์ผ ํ ๋๋ง๋ค ๋๋ต 2๋ฐฐ์ฉ ๋๋ฆฐ๋ค.
*/
private void ensureCapacity()
{
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
// ๋ฉ๋ชจ๋ฆฌ ๋์ ์์ด ์ ๋๋ก ๊ตฌํํ pop ๋ฉ์๋
public Object pop()
{
if (size == 0) {
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null; // ๋ฐฉ๋ฒ1) ๋ค ์ด ์ฐธ์กฐ ํด์ -> ๋ฐ๋์งํ ๋ฐฉ๋ฒ์ ์๋๋ค -> ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ null ์ฒ๋ฆฌํ๋ ์ผ์ ์์ธ์ ์ด์ด์ผ ํ๋ค.
return result;
}
public static void main(String[] args)
{
Stack stack = new Stack();
for (String arg : args)
{
stack.push(arg);
}
while (true)
{
System.out.println("stack.pop() = " + stack.pop());
}
}
}
-> elements[size] = null ๋ก ์ฒ๋ฆฌํ๋ฉด์ ๋ค ์ด ์ฐธ์กฐ๋ฅผ ํด์ ํด์คฌ๋๋ฐ ์ด๋ ๊ฒ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ null ์ฒ๋ฆฌํ๋ ์ผ์ ์์ธ์ ์ธ ๊ฒฝ์ฐ์ฌ์ผ ํ๋ค!!
ํด๊ฒฐ ๋ฐฉ๋ฒ 2) ๊ทธ ์ฐธ์กฐ๋ฅผ ๋ด์ ๋ณ์๋ฅผ ์ ํจ ๋ฒ์(scope) ๋ฐ์ผ๋ก ๋ฐ์ด๋ด๋ ๊ฒ์ด๋ค.
๋ณ์์ ๋ฒ์๋ฅผ ์ต์๊ฐ ๋๊ฒ ์ ์ํด์ ๋ ์ด์ ์ฐธ์กฐํ์ง ์์ ๊ฒฝ์ฐ์๋ ์ ํจ ๋ฒ์ ๋ฐ์ผ๋ก ๋ฐ์ด๋ด์ ๋ค ์ด ์ฐธ์กฐ ๊ฐ์ฒด๋ฅผ ํด์ ํ ์ ์๋ค.
์ผ๋ฐ์ ์ผ๋ก ์๊ธฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ํด๋์ค๋ผ๋ฉด ํ๋ก๊ทธ๋๋จธ๋ ํญ์ ๋ฉ๋ชจ๋ฆฌ ๋์์ ์ฃผ์ํด์ผ ํ๋ค.
- cache
์์ ์์์์๋ ์คํ์ ์๋ก ๋ค์๋๋ฐ ์บ์ ์ญ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ผ์ผํค๋ ์ฃผ๋ฒ์ด๋ค.
์บ์ ์ญ์ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์บ์์ ๋ฃ๊ณ ๋์ ์ด ์ฌ์ค์ ๊น๋จน๊ณ ์๋ค๊ฐ ๊ทธ ๊ฐ์ฒด๋ฅผ ๋ค ์ด ๋ค๋ก๋ ํ์ฐธ ๊ทธ๋๋ก ๋๋๊ฒ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
package chapter01.item07.cache;
import java.time.LocalDateTime;
public class CacheKey
{
private Integer value;
private LocalDateTime created;
public CacheKey(Integer value)
{
this.value = value;
this.created = LocalDateTime.now();
}
@Override
public boolean equals(Object obj)
{
return this.value.equals(obj);
}
@Override
public int hashCode()
{
return this.value.hashCode();
}
public LocalDateTime getCreated()
{
return created;
}
@Override
public String toString()
{
return "CacheKey{" +
"value=" + value +
", created=" + created +
'}';
}
}
package chapter01.item07.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.springframework.cglib.core.WeakCacheKey;
/**
* item07. ๋ค ์ด ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
*/
public class PostRepository
{
private Map<CacheKey, Post> cache;
public PostRepository()
{
this.cache = new HashMap<>();
}
public Post getPostById(Integer id)
{
CacheKey key = new CacheKey(id);
if (cache.containsKey(key)) {
return cache.get(key);
}else {
Post post = new Post(); // TODO DB์์ ์ฝ์ด์ค๊ฑฐ๋ REST API๋ฅผ ํตํด ์ฝ์ด์ฌ ์ ์๋ค.
cache.put(key, post);
return post;
}
}
public Map<CacheKey, Post> getCache()
{
return cache;
}
}
@Test
void cache() throws InterruptedException
{
PostRepository postRepository = new PostRepository();
Integer p1 = 1;
postRepository.getPostById(p1);
assertFalse(postRepository.getCache().isEmpty());
System.out.println("run gc");
System.gc();
System.out.println("wait");
Thread.sleep(3000L);
assertTrue(postRepository.getCache().isEmpty());
}
์ด๋ ๊ฒ ๊ตฌํํ ํ์ ์บ์๋ฅผ ํ ์คํธ ํด๋ณด๋ฉด ๊ฐ๋น์ง ์ปฌ๋ ์ ์์ ์บ์๋ ์ฐธ์กฐํ๊ณ ์๋ ๊ณณ์ด ์๊ธฐ ๋๋ฌธ์ GC์ ๋์์ด ๋์ง ์์์ assertTrue์์ ํ ์คํธ ์คํจํ๋ค. (false ์ด๊ธฐ ๋๋ฌธ์)
package chapter01.item07.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.springframework.cglib.core.WeakCacheKey;
/**
* item07. ๋ค ์ด ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
*/
public class PostRepository
{
private Map<CacheKey, Post> cache;
public PostRepository()
{
this.cache = new WeakHashMap<>();
}
public Post getPostById(Integer id)
{
CacheKey key = new CacheKey(id);
if (cache.containsKey(key)) {
return cache.get(key);
}else {
Post post = new Post(); // TODO DB์์ ์ฝ์ด์ค๊ฑฐ๋ REST API๋ฅผ ํตํด ์ฝ์ด์ฌ ์ ์๋ค.
cache.put(key, post);
return post;
}
}
public Map<CacheKey, Post> getCache()
{
return cache;
}
}
์ฑ ์ ๋ณด๋ฉด 'ํค๋ฅผ ์ฐธ์กฐํ๋ ๋์๋ง ์ํธ๋ฆฌ๊ฐ ์ด์ด ์๋ ์บ์๊ฐ ํ์ํ ์ํฉ์ด๋ผ๋ฉด WeakHashMap์ ์ฌ์ฉํด ์บ์๋ฅผ ๋ง๋ค์'
๋ผ๋ ๋ง์ด ์๋๋ฐ ์ด์ ๊ฐ์ด ์๋๋ HashMap์ ์ฌ์ฉํ์ ๋๋ ํ ์คํธ ์คํจํ์ง๋ง,, WeakHashMap์ ์ฌ์ฉํ๋ฉด ๋ค ์ด ์ํธ๋ฆฌ๋ ์ฆ์ ์๋์ผ๋ก ์ ๊ฑฐ๊ฐ ๋ผ์ ํ ์คํธ ์ฑ๊ณตํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๐ก WeakHashMap์ ์์ง ์ ๋ชฐ๋ผ์ ์ฌ์ค ์ด ๋ถ๋ถ์ ์ดํด๊ฐ ๋์ง ์์๋ค,, ๋ค์ ๊ฐ์์ ์ค๋ช ์ด ์์ด์ ๋ฃ๊ณ ๋ด์ฉ์ ๋ ์ถ๊ฐํด์ผ๊ฒ ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ3) ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋ ํ์ฉํ๋ ๋ฐฉ๋ฒ
@Test
void backgroundThread() throws InterruptedException
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
PostRepository postRepository = new PostRepository();
CacheKey key1 = new CacheKey(1);
postRepository.getPostById(1);
Runnable removeOldCache = () -> {
System.out.println("running removeOldCache task");
Map<CacheKey, Post> cache = postRepository.getCache();
Set<CacheKey> cacheKeys = cache.keySet();
Optional<CacheKey> key = cacheKeys.stream()
.min(Comparator.comparing(CacheKey::getCreated));
key.ifPresent((k)-> {
System.out.println("removing " + k);
cache.remove(k);
});
};
System.out.println("The time is : " + new Date());
executor.scheduleAtFixedRate(removeOldCache, 1, 3,
TimeUnit.SECONDS);
Thread.sleep(20000L);
executor.shutdown();
}
ScheduledThreadPoolExecutor๋ฅผ ํตํด ์ฐ์ง ์์ ์ํธ๋ฆฌ๋ฅผ ์ ๊ฑฐํ๋ ๊ณผ์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํ ์คํธ ์ํ ๊ฒฐ๊ณผ ์ฒ์์๋ ์ ๊ฑฐํ ์ํธ๋ฆฌ๊ฐ ์์ด์ ์ ๊ฑฐํ ํ์๋ ์ด์ ๋ ์ด์ ์ ๊ฑฐํ ๊ฒ์ด ์๊ธฐ ๋๋ฌธ์ 'running removeOldCache task' ๋ง ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธ ํ ์ ์๋ค.
- ๋ฆฌ์ค๋ (listener) , ์ฝ๋ฐฑ (callback)
: ๋ฉ๋ชจ๋ฆฌ ๋์์ ์ธ๋ฒใ ?ใ ์ฃผ๋ฒ์ ๋ฐ๋ก ๋ฆฌ์ค๋ ํน์ ์ฝ๋ฐฑ์ด๋ผ ๋ถ๋ฅด๋ ๊ฒ์ด๋ค.
ํด๋ผ์ด์ธํธ์นด ์ฝ๋ฐฑ์ ๋ฑ๋ก๋ง ํ๊ณ ๋ช ํํ๊ฒ ํด์งํ์ง ์๋๋ค๋ฉด ๋ญ๊ฐ ์กฐ์นํด์ฃผ์ง ์๋ ํ ์ฝ๋ฐฑ์ ์ ๊ฑฐ๋์ง ์๊ณ ๊ณ์ ์์ด๊ฒ๋ง ๋๋ค..
-> ์ด๋ด ๋๋ ์ฝ๋ฐฑ์ ์ฝํ ์ฐธ์กฐ (Weak reference)๋ก ์ ์ฅํ๋ฉด ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ์ฆ์ ์๊ฑฐํด๊ฐ๋ค. (ex. WeakHashMap ์ ํค๋ก ์ ์ฅ)
'JAVA > Effective JAVA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ดํํฐ๋ธ ์๋ฐ] Item07 ์๋ฒฝ๊ณต๋ต. WeakHashMap (0) | 2023.01.21 |
---|---|
[์ดํํฐ๋ธ ์๋ฐ] Item07 ์๋ฒฝ๊ณต๋ต.NullPointerException (0) | 2023.01.21 |
[์ดํํฐ๋ธ ์๋ฐ] Item06 ์๋ฒฝ๊ณต๋ต. ๊ฐ๋น์ง ์ปฌ๋ ์ Garbage Collection GC (0) | 2023.01.19 |
[์ดํํฐ๋ธ ์๋ฐ] Item06 ์๋ฒฝ๊ณต๋ต. ์ ๊ท ํํ์ (0) | 2023.01.19 |
[์ดํํฐ๋ธ ์๋ฐ] Item06 ์๋ฒฝ๊ณต๋ต. Deprecation (0) | 2023.01.19 |