#10 effective java: item 7

This commit is contained in:
haerong22
2022-05-25 02:11:12 +09:00
parent 8188d0fc15
commit fe6feed168
9 changed files with 287 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
package com.example.effectivejava.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 o) {
return this.value.equals(o);
}
@Override
public int hashCode() {
return this.value.hashCode();
}
public LocalDateTime getCreated() {
return created;
}
@Override
public String toString() {
return "CacheKey{" +
"value=" + value +
", created=" + created +
'}';
}
}

View File

@@ -0,0 +1,39 @@
package com.example.effectivejava.chapter01.item07.cache;
public class Post {
private Integer id;
private String title;
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public void finalize() {
System.out.println("gc called");
}
}

View File

@@ -0,0 +1,28 @@
package com.example.effectivejava.chapter01.item07.cache;
import java.util.Map;
import java.util.WeakHashMap;
public class PostRepository {
private Map<CacheKey, Post> cache;
public PostRepository() {
this.cache = new WeakHashMap<>();
}
public Post getPostById(CacheKey key) {
if (cache.containsKey(key)) {
return cache.get(key);
} else {
// TODO DB에서 읽어오거나 REST API를 통해 읽어올 수 있습니다.
Post post = new Post();
cache.put(key, post);
return post;
}
}
public Map<CacheKey, Post> getCache() {
return cache;
}
}

View File

@@ -0,0 +1,27 @@
package com.example.effectivejava.chapter01.item07.listener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ChatRoom {
private List<WeakReference<User>> users;
public ChatRoom() {
this.users = new ArrayList<>();
}
public void addUser(User user) {
this.users.add(new WeakReference<>(user));
}
public void sendMessage(String message) {
users.forEach(wr -> Objects.requireNonNull(wr.get()).receive(message));
}
public List<WeakReference<User>> getUsers() {
return users;
}
}

View File

@@ -0,0 +1,8 @@
package com.example.effectivejava.chapter01.item07.listener;
public class User {
public void receive(String message) {
System.out.println(message);
}
}

View File

@@ -0,0 +1,5 @@
package com.example.effectivejava.chapter01.item07.stack;
// (36쪽의 Stack 코드에서 던지는 예외)
public class EmptyStackException extends IllegalStateException {
}

View File

@@ -0,0 +1,52 @@
package com.example.effectivejava.chapter01.item07.stack;
import java.util.Arrays;
// 코드 7-1 메모리 누수가 일어나는 위치는 어디인가? (36쪽)
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];
// }
/**
* 원소를 위한 공간을 적어도 하나 이상 확보한다.
* 배열 크기를 늘려야 할 때마다 대략 두 배씩 늘린다.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
// 코드 7-2 제대로 구현한 pop 메서드 (37쪽)
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
public static void main(String[] args) {
Stack stack = new Stack();
for (String arg : args)
stack.push(arg);
while (true)
System.err.println(stack.pop());
}
}

View File

@@ -0,0 +1,59 @@
package com.example.effectivejava.chapter01.item07.cache;
import org.junit.jupiter.api.Test;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
class PostRepositoryTest {
@Test
void cache() throws InterruptedException {
PostRepository postRepository = new PostRepository();
CacheKey key1 = new CacheKey(1);
postRepository.getPostById(key1);
assertFalse(postRepository.getCache().isEmpty());
key1 = null;
// TODO run gc
System.out.println("run gc");
System.gc();
System.out.println("wait");
Thread.sleep(3000L);
assertTrue(postRepository.getCache().isEmpty());
}
@Test
void backgroundThread() throws InterruptedException {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
PostRepository postRepository = new PostRepository();
CacheKey key1 = new CacheKey(1);
postRepository.getPostById(key1);
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();
}
}

View File

@@ -0,0 +1,32 @@
package com.example.effectivejava.chapter01.item07.listener;
import org.junit.jupiter.api.Test;
import java.lang.ref.WeakReference;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class ChatRoomTest {
@Test
void charRoom() throws InterruptedException {
ChatRoom chatRoom = new ChatRoom();
User user1 = new User();
User user2 = new User();
chatRoom.addUser(user1);
chatRoom.addUser(user2);
chatRoom.sendMessage("hello");
user1 = null;
System.gc();
Thread.sleep(5000L);
List<WeakReference<User>> users = chatRoom.getUsers();
assertEquals(1, users.size());
}
}