Last active
March 9, 2017 08:55
-
-
Save redutan/74cadc3f36055c8e34b9cb72c514eff9 to your computer and use it in GitHub Desktop.
NotThreadSafeTest
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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