Skip to content

Instantly share code, notes, and snippets.

@redutan
Last active March 9, 2017 08:55
Show Gist options
  • Save redutan/74cadc3f36055c8e34b9cb72c514eff9 to your computer and use it in GitHub Desktop.
Save redutan/74cadc3f36055c8e34b9cb72c514eff9 to your computer and use it in GitHub Desktop.
NotThreadSafeTest
@Slf4j
public class NotThreadSafeTest {
Map<Integer, Integer> resourceMap;
Map<String, Integer> resourceMap2;
@Test
public void testNotThreadSafe_HashMapPut() throws Exception {
// given
final int size = 1_000_000;
resourceMap = new HashMap<>();
ExecutorService executorService = Executors.newFixedThreadPool(5);
Collection<Callable<Integer>> callables = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final int num = i;
callables.add(() -> resourceMap.put(num, num));
}
// when
executorService.invokeAll(callables);
log.info("after invokeAll");
// then
assertThat(resourceMap.size(), is(lessThan(size))); // Thread safe 하지 않기 때문에 사이즈가 적다
}
@Test
public void testThreadSafe_ConcurrentHashMapPut() throws Exception {
// given
final int size = 1_000_000;
resourceMap = new ConcurrentHashMap<>();
ExecutorService executorService = Executors.newFixedThreadPool(5);
Collection<Callable<Integer>> callables = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final int num = i;
callables.add(() -> resourceMap.put(num, num));
}
// when
executorService.invokeAll(callables);
log.info("after invokeAll");
// then
assertThat(resourceMap.size(), is(size)); // Thread safe 하므로 사이즈가 같다
}
// @Test(expected = AssertionError.class)
// public void testNotThreadSafe_HashMapGet() throws Exception {
// // given
// final int size = 2;
// resourceMap2 = new HashMap<>();
// resourceMap2.put("AaAa", 1);
// resourceMap2.put("BBBB", 2);
// resourceMap2.put("AaBB", 3);
// resourceMap2.put("BBAa", 4);
//
//
// ExecutorService executorService = Executors.newFixedThreadPool(5);
// final int callSize = 1_000_000;
// Collection<Callable<Integer>> callables = new ArrayList<>(callSize);
// for (int i = 0; i < callSize; i++) {
// final HashKey intObj = new HashKey(i % size);
// callables.add(() -> resourceMap2.get(intObj));
// }
//
// // when
// List<Future<Integer>> futures = executorService.invokeAll(callables);
// log.info("after invokeAll");
//
// // then
// int i = 0;
// for (Future<Integer> future : futures) {
// Integer num = future.get();
// assertThat(num, is(i % size)); // 실패가 나야하는데 안나네????
// i++;
// }
// }
@Test(expected = AssertionError.class)
public void testNotThreadSafe_HashMapGet2() throws Exception {
// given
resourceMap2 = new HashMap<>();
resourceMap2.put("AaAa", 1);
resourceMap2.put("BBBB", 2);
resourceMap2.put("AaBB", 3);
resourceMap2.put("1234", 4);
// Some key's hasCode is same
resourceMap2.keySet().stream().mapToInt(String::hashCode).forEach(System.out::println);
ExecutorService executorService = Executors.newFixedThreadPool(8);
final int callSize = 500_000_000;
executorService.execute(() -> {
log.info("run 0");
boolean result = IntStream.range(0, callSize).parallel()
.mapToObj(i -> "AaAa")
.map(resourceMap2::get)
.allMatch(i -> i.equals(1));
assertThat(result, is(true));
log.info("run complete 0");
});
executorService.execute(() -> {
log.info("run 1");
boolean result = IntStream.range(0, callSize).parallel()
.mapToObj(i -> "BBBB")
.map(resourceMap2::get)
.allMatch(i -> i.equals(2));
assertThat(result, is(true));
log.info("run complete 1");
});
executorService.execute(() -> {
log.info("run 2");
boolean result = IntStream.range(0, callSize).parallel()
.mapToObj(i -> "AaBB")
.map(resourceMap2::get)
.allMatch(i -> i.equals(3));
assertThat(result, is(true));
log.info("run complete 2");
});
executorService.execute(() -> {
log.info("run 3");
boolean result = IntStream.range(0, callSize).parallel()
.mapToObj(i -> "1234")
.map(resourceMap2::get)
.allMatch(i -> i.equals(4));
assertThat(result, is(true));
log.info("run complete 3");
});
executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);
executorService.shutdown();
}
// @Test
// public void testThreadSafe_ConcurrentHashMapGet() throws Exception {
// // given
// final int size = 2;
// resourceMap2 = createReserveMap(size, ConcurrentHashMap::new);
//
// ExecutorService executorService = Executors.newFixedThreadPool(4);
// final int callSize = 1_000_000;
// Collection<Callable<Integer>> callables = new ArrayList<>(callSize);
// for (int i = 0; i < callSize; i++) {
// final HashKey intObj = new HashKey(i % size);
// callables.add(() -> resourceMap2.get(intObj));
// }
//
// // when
// List<Future<Integer>> futures = executorService.invokeAll(callables);
//
// // then
// int i = 0;
// for (Future<Integer> future : futures) {
// Integer num = future.get();
// assertThat(num, is(i % size));
// i++;
// }
// }
private Map<HashKey, Integer> createReserveMap(int size, Supplier<Map<HashKey, Integer>> mapSupplier) {
Map<HashKey, Integer> result = mapSupplier.get();
for (int i = 0; i < size; i++) {
result.put(new HashKey(i), i);
}
return result;
}
@Value
private static class HashKey {
private int value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment