PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/core/petra/petra-lang/src/test/java/com/liferay/petra/lang/CentralizedThreadLocalTest.java

http://github.com/liferay/liferay-portal
Java | 657 lines | 392 code | 225 blank | 40 comment | 2 complexity | e98702acc065479448ef52ad849d6cc1 MD5 | raw file
Possible License(s): LGPL-2.0
  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. package com.liferay.petra.lang;
  15. import com.liferay.portal.kernel.test.ReflectionTestUtil;
  16. import com.liferay.portal.kernel.test.rule.AggregateTestRule;
  17. import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
  18. import com.liferay.portal.test.rule.LiferayUnitTestRule;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Random;
  24. import java.util.concurrent.BlockingQueue;
  25. import java.util.concurrent.FutureTask;
  26. import java.util.concurrent.SynchronousQueue;
  27. import java.util.concurrent.atomic.AtomicInteger;
  28. import java.util.function.Function;
  29. import org.junit.Assert;
  30. import org.junit.ClassRule;
  31. import org.junit.Rule;
  32. import org.junit.Test;
  33. /**
  34. * @author Shuyang Zhou
  35. */
  36. public class CentralizedThreadLocalTest {
  37. @ClassRule
  38. @Rule
  39. public static final AggregateTestRule aggregateTestRule =
  40. new AggregateTestRule(
  41. new CodeCoverageAssertor() {
  42. @Override
  43. public void appendAssertClasses(List<Class<?>> assertClasses) {
  44. assertClasses.add(SafeClosable.class);
  45. assertClasses.add(SafeCloseable.class);
  46. }
  47. },
  48. LiferayUnitTestRule.INSTANCE);
  49. @Test
  50. public void testCopy() {
  51. // No copy
  52. Object object = new Object();
  53. CentralizedThreadLocal<Object> centralizedThreadLocal =
  54. new CentralizedThreadLocal<>(false);
  55. centralizedThreadLocal.set(object);
  56. Map<CentralizedThreadLocal<?>, Object> longLivedThreadLocals =
  57. CentralizedThreadLocal.getLongLivedThreadLocals();
  58. Map<CentralizedThreadLocal<?>, Object> shortLivedThreadLocals =
  59. CentralizedThreadLocal.getShortLivedThreadLocals();
  60. centralizedThreadLocal.remove();
  61. CentralizedThreadLocal.setThreadLocals(
  62. longLivedThreadLocals, shortLivedThreadLocals);
  63. Assert.assertNull(centralizedThreadLocal.get());
  64. centralizedThreadLocal.remove();
  65. // Explicit copy
  66. centralizedThreadLocal = new CentralizedThreadLocal<>(
  67. null, null, Function.identity(), false);
  68. centralizedThreadLocal.set(object);
  69. longLivedThreadLocals =
  70. CentralizedThreadLocal.getLongLivedThreadLocals();
  71. shortLivedThreadLocals =
  72. CentralizedThreadLocal.getShortLivedThreadLocals();
  73. centralizedThreadLocal.remove();
  74. CentralizedThreadLocal.setThreadLocals(
  75. longLivedThreadLocals, shortLivedThreadLocals);
  76. Assert.assertSame(object, centralizedThreadLocal.get());
  77. centralizedThreadLocal.remove();
  78. // Default copy
  79. String testString = "test";
  80. centralizedThreadLocal = new CentralizedThreadLocal<>(false);
  81. centralizedThreadLocal.set(testString);
  82. longLivedThreadLocals =
  83. CentralizedThreadLocal.getLongLivedThreadLocals();
  84. shortLivedThreadLocals =
  85. CentralizedThreadLocal.getShortLivedThreadLocals();
  86. centralizedThreadLocal.remove();
  87. CentralizedThreadLocal.setThreadLocals(
  88. longLivedThreadLocals, shortLivedThreadLocals);
  89. Assert.assertSame(testString, centralizedThreadLocal.get());
  90. centralizedThreadLocal.remove();
  91. // Null copy
  92. centralizedThreadLocal = new CentralizedThreadLocal<>(false);
  93. centralizedThreadLocal.set(null);
  94. longLivedThreadLocals =
  95. CentralizedThreadLocal.getLongLivedThreadLocals();
  96. shortLivedThreadLocals =
  97. CentralizedThreadLocal.getShortLivedThreadLocals();
  98. centralizedThreadLocal.remove();
  99. CentralizedThreadLocal.setThreadLocals(
  100. longLivedThreadLocals, shortLivedThreadLocals);
  101. Assert.assertNull(centralizedThreadLocal.get());
  102. centralizedThreadLocal.remove();
  103. }
  104. @Test
  105. public void testEquals() {
  106. CentralizedThreadLocal<?> centralizedThreadLocal1 =
  107. new CentralizedThreadLocal<>(false);
  108. Assert.assertFalse(centralizedThreadLocal1.equals(new Object()));
  109. Assert.assertTrue(
  110. centralizedThreadLocal1.equals(centralizedThreadLocal1));
  111. CentralizedThreadLocal<?> centralizedThreadLocal2 =
  112. new CentralizedThreadLocal<>(false);
  113. Assert.assertFalse(
  114. centralizedThreadLocal1.equals(centralizedThreadLocal2));
  115. }
  116. @Test
  117. public void testHashCode() {
  118. AtomicInteger longLivedNextHasCode = ReflectionTestUtil.getFieldValue(
  119. CentralizedThreadLocal.class, "_longLivedNextHasCode");
  120. AtomicInteger shortLivedNextHasCode = ReflectionTestUtil.getFieldValue(
  121. CentralizedThreadLocal.class, "_shortLivedNextHasCode");
  122. Random random = new Random();
  123. int longLivedHashCode = random.nextInt();
  124. int shortLivedHashCode = random.nextInt();
  125. longLivedNextHasCode.set(longLivedHashCode);
  126. shortLivedNextHasCode.set(shortLivedHashCode);
  127. CentralizedThreadLocal<?> longLivedCentralizedThreadLocal =
  128. new CentralizedThreadLocal<>(false);
  129. CentralizedThreadLocal<?> shortLivedCentralizedThreadLocal =
  130. new CentralizedThreadLocal<>(true);
  131. Assert.assertEquals(
  132. longLivedHashCode, longLivedCentralizedThreadLocal.hashCode());
  133. Assert.assertEquals(
  134. shortLivedHashCode, shortLivedCentralizedThreadLocal.hashCode());
  135. longLivedCentralizedThreadLocal = new CentralizedThreadLocal<>(false);
  136. shortLivedCentralizedThreadLocal = new CentralizedThreadLocal<>(true);
  137. int hashIncrement = ReflectionTestUtil.getFieldValue(
  138. CentralizedThreadLocal.class, "_HASH_INCREMENT");
  139. Assert.assertEquals(
  140. longLivedHashCode + hashIncrement,
  141. longLivedCentralizedThreadLocal.hashCode());
  142. Assert.assertEquals(
  143. shortLivedHashCode + hashIncrement,
  144. shortLivedCentralizedThreadLocal.hashCode());
  145. Assert.assertEquals(
  146. longLivedHashCode + (hashIncrement * 2),
  147. longLivedNextHasCode.get());
  148. Assert.assertEquals(
  149. shortLivedHashCode + (hashIncrement * 2),
  150. shortLivedNextHasCode.get());
  151. }
  152. @Test
  153. public void testInitialValue() {
  154. // By override
  155. Object object = new Object();
  156. CentralizedThreadLocal<?> centralizedThreadLocal =
  157. new CentralizedThreadLocal<Object>(false) {
  158. @Override
  159. protected Object initialValue() {
  160. return object;
  161. }
  162. };
  163. Assert.assertSame(object, centralizedThreadLocal.get());
  164. centralizedThreadLocal.remove();
  165. // By Supplier
  166. centralizedThreadLocal = new CentralizedThreadLocal<>(
  167. null, () -> object);
  168. Assert.assertSame(object, centralizedThreadLocal.get());
  169. centralizedThreadLocal.remove();
  170. // By null Supplier
  171. centralizedThreadLocal = new CentralizedThreadLocal<>(null, null);
  172. Assert.assertNull(centralizedThreadLocal.get());
  173. centralizedThreadLocal.remove();
  174. }
  175. @Test
  176. public void testSetWithClosable() {
  177. String initialValue = "initialValue";
  178. CentralizedThreadLocal<String> centralizedThreadLocal =
  179. new CentralizedThreadLocal<>("test", () -> initialValue);
  180. String value1 = "value1";
  181. try (SafeClosable safeClosable =
  182. centralizedThreadLocal.setWithSafeClosable(value1)) {
  183. Assert.assertSame(value1, centralizedThreadLocal.get());
  184. }
  185. Assert.assertSame(initialValue, centralizedThreadLocal.get());
  186. String value2 = "value2";
  187. try (SafeClosable safeClosable1 =
  188. centralizedThreadLocal.setWithSafeClosable(value1)) {
  189. try (SafeClosable safeClosable2 =
  190. centralizedThreadLocal.setWithSafeClosable(value2)) {
  191. Assert.assertSame(value2, centralizedThreadLocal.get());
  192. }
  193. Assert.assertSame(value1, centralizedThreadLocal.get());
  194. }
  195. Assert.assertSame(initialValue, centralizedThreadLocal.get());
  196. }
  197. @Test
  198. public void testSetWithCloseable() {
  199. String initialValue = "initialValue";
  200. CentralizedThreadLocal<String> centralizedThreadLocal =
  201. new CentralizedThreadLocal<>("test", () -> initialValue);
  202. String value1 = "value1";
  203. try (SafeCloseable safeCloseable =
  204. centralizedThreadLocal.setWithSafeCloseable(value1)) {
  205. Assert.assertSame(value1, centralizedThreadLocal.get());
  206. }
  207. Assert.assertSame(initialValue, centralizedThreadLocal.get());
  208. String value2 = "value2";
  209. try (SafeCloseable safeCloseable1 =
  210. centralizedThreadLocal.setWithSafeCloseable(value1)) {
  211. try (SafeCloseable safeCloseable2 =
  212. centralizedThreadLocal.setWithSafeCloseable(value2)) {
  213. Assert.assertSame(value2, centralizedThreadLocal.get());
  214. }
  215. Assert.assertSame(value1, centralizedThreadLocal.get());
  216. }
  217. Assert.assertSame(initialValue, centralizedThreadLocal.get());
  218. }
  219. @Test
  220. public void testThreadLocalManagement() {
  221. // Initial clean up
  222. CentralizedThreadLocal.clearLongLivedThreadLocals();
  223. CentralizedThreadLocal.clearShortLivedThreadLocals();
  224. // Lazy registration
  225. CentralizedThreadLocal<String> longLiveCentralizedThreadLocal =
  226. new CentralizedThreadLocal<>(false);
  227. CentralizedThreadLocal<String> shortLivedCentralizedThreadLocal =
  228. new CentralizedThreadLocal<>(true);
  229. Map<CentralizedThreadLocal<?>, Object> longLivedThreadLocals =
  230. CentralizedThreadLocal.getLongLivedThreadLocals();
  231. Assert.assertTrue(
  232. longLivedThreadLocals.toString(), longLivedThreadLocals.isEmpty());
  233. Map<CentralizedThreadLocal<?>, Object> shortLivedThreadLocals =
  234. CentralizedThreadLocal.getShortLivedThreadLocals();
  235. Assert.assertTrue(
  236. shortLivedThreadLocals.toString(),
  237. shortLivedThreadLocals.isEmpty());
  238. // Trigger registration
  239. longLiveCentralizedThreadLocal.set("longLive");
  240. longLivedThreadLocals =
  241. CentralizedThreadLocal.getLongLivedThreadLocals();
  242. Assert.assertEquals(
  243. "longLive",
  244. longLivedThreadLocals.get(longLiveCentralizedThreadLocal));
  245. shortLivedThreadLocals =
  246. CentralizedThreadLocal.getShortLivedThreadLocals();
  247. Assert.assertTrue(
  248. shortLivedThreadLocals.toString(),
  249. shortLivedThreadLocals.isEmpty());
  250. shortLivedCentralizedThreadLocal.set("shortLive");
  251. longLivedThreadLocals =
  252. CentralizedThreadLocal.getLongLivedThreadLocals();
  253. Assert.assertEquals(
  254. "longLive",
  255. longLivedThreadLocals.get(longLiveCentralizedThreadLocal));
  256. shortLivedThreadLocals =
  257. CentralizedThreadLocal.getShortLivedThreadLocals();
  258. Assert.assertEquals(
  259. "shortLive",
  260. shortLivedThreadLocals.get(shortLivedCentralizedThreadLocal));
  261. // Clean up
  262. CentralizedThreadLocal.clearLongLivedThreadLocals();
  263. CentralizedThreadLocal.clearShortLivedThreadLocals();
  264. longLivedThreadLocals =
  265. CentralizedThreadLocal.getLongLivedThreadLocals();
  266. Assert.assertTrue(
  267. longLivedThreadLocals.toString(), longLivedThreadLocals.isEmpty());
  268. shortLivedThreadLocals =
  269. CentralizedThreadLocal.getShortLivedThreadLocals();
  270. Assert.assertTrue(
  271. shortLivedThreadLocals.toString(),
  272. shortLivedThreadLocals.isEmpty());
  273. // Set threadlocals
  274. CentralizedThreadLocal.setThreadLocals(
  275. Collections.singletonMap(
  276. longLiveCentralizedThreadLocal, "longLive"),
  277. Collections.singletonMap(
  278. shortLivedCentralizedThreadLocal, "shortLive"));
  279. longLivedThreadLocals =
  280. CentralizedThreadLocal.getLongLivedThreadLocals();
  281. Assert.assertEquals(
  282. "longLive",
  283. longLivedThreadLocals.get(longLiveCentralizedThreadLocal));
  284. shortLivedThreadLocals =
  285. CentralizedThreadLocal.getShortLivedThreadLocals();
  286. Assert.assertEquals(
  287. "shortLive",
  288. shortLivedThreadLocals.get(shortLivedCentralizedThreadLocal));
  289. // Clean up
  290. CentralizedThreadLocal.clearLongLivedThreadLocals();
  291. CentralizedThreadLocal.clearShortLivedThreadLocals();
  292. }
  293. @Test
  294. public void testThreadLocalMap() {
  295. // Auto expanding with hashcode confliction
  296. AtomicInteger shortLivedNextHasCode = ReflectionTestUtil.getFieldValue(
  297. CentralizedThreadLocal.class, "_shortLivedNextHasCode");
  298. Random random = new Random();
  299. int shortLivedHashCode = random.nextInt();
  300. for (int i = 0; i < 17; i++) {
  301. shortLivedNextHasCode.set(shortLivedHashCode);
  302. CentralizedThreadLocal<String> centralizedThreadLocal =
  303. new CentralizedThreadLocal<>(true);
  304. centralizedThreadLocal.set(String.valueOf(i));
  305. }
  306. ThreadLocal<Object> shortLivedThreadLocals =
  307. ReflectionTestUtil.getFieldValue(
  308. CentralizedThreadLocal.class, "_shortLivedThreadLocals");
  309. Object threadLocalMap = shortLivedThreadLocals.get();
  310. Object[] table = ReflectionTestUtil.getFieldValue(
  311. threadLocalMap, "_table");
  312. Assert.assertEquals(Arrays.toString(table), 32, table.length);
  313. Assert.assertEquals(
  314. Integer.valueOf(32 * 2 / 3),
  315. ReflectionTestUtil.getFieldValue(threadLocalMap, "_threshold"));
  316. CentralizedThreadLocal.clearShortLivedThreadLocals();
  317. // Auto expanding upper threshold
  318. int newCapacity = 1 << 31;
  319. ReflectionTestUtil.invoke(
  320. threadLocalMap, "expand", new Class<?>[] {int.class}, newCapacity);
  321. Assert.assertEquals(
  322. Integer.valueOf(Integer.MAX_VALUE),
  323. ReflectionTestUtil.getFieldValue(threadLocalMap, "_threshold"));
  324. // Hash code confliction set/get/remove
  325. shortLivedNextHasCode.set(shortLivedHashCode);
  326. CentralizedThreadLocal<String> centralizedThreadLocal1 =
  327. new CentralizedThreadLocal<>(true);
  328. shortLivedNextHasCode.set(shortLivedHashCode);
  329. CentralizedThreadLocal<String> centralizedThreadLocal2 =
  330. new CentralizedThreadLocal<>(true);
  331. Assert.assertEquals(
  332. centralizedThreadLocal1.hashCode(),
  333. centralizedThreadLocal2.hashCode());
  334. shortLivedNextHasCode.set(shortLivedHashCode);
  335. CentralizedThreadLocal<String> centralizedThreadLocal3 =
  336. new CentralizedThreadLocal<>(true);
  337. Assert.assertEquals(
  338. centralizedThreadLocal2.hashCode(),
  339. centralizedThreadLocal3.hashCode());
  340. centralizedThreadLocal1.set("test1");
  341. centralizedThreadLocal2.set("test2");
  342. Assert.assertNull(centralizedThreadLocal3.get());
  343. Assert.assertEquals("test2", centralizedThreadLocal2.get());
  344. Assert.assertEquals("test1", centralizedThreadLocal1.get());
  345. centralizedThreadLocal2.remove();
  346. Assert.assertEquals("test1", centralizedThreadLocal1.get());
  347. Assert.assertNull(centralizedThreadLocal2.get());
  348. centralizedThreadLocal1.remove();
  349. Assert.assertNull(centralizedThreadLocal1.get());
  350. Assert.assertNull(centralizedThreadLocal2.get());
  351. // Empty remove
  352. CentralizedThreadLocal<String> centralizedThreadLocal4 =
  353. new CentralizedThreadLocal<>(true);
  354. centralizedThreadLocal4.remove();
  355. }
  356. @Test
  357. public void testThreadSeparation() throws Exception {
  358. CentralizedThreadLocal<String> centralizedThreadLocal =
  359. new CentralizedThreadLocal<>(false);
  360. FutureTask<?> poisonFutureTask = new FutureTask<>(() -> null);
  361. BlockingQueue<FutureTask<?>> blockingQueue = new SynchronousQueue<>();
  362. FutureTask<Void> threadFutureTask = new FutureTask<>(
  363. () -> {
  364. FutureTask<?> futureTask = null;
  365. while ((futureTask = blockingQueue.take()) !=
  366. poisonFutureTask) {
  367. futureTask.run();
  368. }
  369. return null;
  370. });
  371. Thread thread = new Thread(threadFutureTask, "Test Thread");
  372. thread.start();
  373. // Clean get
  374. Assert.assertNull(centralizedThreadLocal.get());
  375. FutureTask<String> getFutureTask = new FutureTask<>(
  376. centralizedThreadLocal::get);
  377. blockingQueue.put(getFutureTask);
  378. Assert.assertNull(getFutureTask.get());
  379. // Set on current thread
  380. centralizedThreadLocal.set("test1");
  381. Assert.assertEquals("test1", centralizedThreadLocal.get());
  382. getFutureTask = new FutureTask<>(centralizedThreadLocal::get);
  383. blockingQueue.put(getFutureTask);
  384. Assert.assertNull(getFutureTask.get());
  385. // Set on test thread
  386. FutureTask<?> setFutureTask = new FutureTask<>(
  387. () -> {
  388. centralizedThreadLocal.set("test2");
  389. return null;
  390. });
  391. blockingQueue.put(setFutureTask);
  392. setFutureTask.get();
  393. Assert.assertEquals("test1", centralizedThreadLocal.get());
  394. getFutureTask = new FutureTask<>(centralizedThreadLocal::get);
  395. blockingQueue.put(getFutureTask);
  396. Assert.assertEquals("test2", getFutureTask.get());
  397. // Remove on current thread
  398. centralizedThreadLocal.remove();
  399. Assert.assertNull(centralizedThreadLocal.get());
  400. getFutureTask = new FutureTask<>(centralizedThreadLocal::get);
  401. blockingQueue.put(getFutureTask);
  402. Assert.assertEquals("test2", getFutureTask.get());
  403. // Remove on test thread
  404. FutureTask<?> removeFutureTask = new FutureTask<>(
  405. () -> {
  406. centralizedThreadLocal.remove();
  407. return null;
  408. });
  409. blockingQueue.put(removeFutureTask);
  410. removeFutureTask.get();
  411. Assert.assertNull(centralizedThreadLocal.get());
  412. getFutureTask = new FutureTask<>(centralizedThreadLocal::get);
  413. blockingQueue.put(getFutureTask);
  414. Assert.assertNull(getFutureTask.get());
  415. // Shutdown test thread
  416. blockingQueue.put(poisonFutureTask);
  417. threadFutureTask.get();
  418. // Clean up
  419. centralizedThreadLocal.remove();
  420. }
  421. @Test
  422. public void testToString() {
  423. CentralizedThreadLocal<?> centralizedThreadLocal =
  424. new CentralizedThreadLocal<>("test");
  425. Assert.assertEquals("test", centralizedThreadLocal.toString());
  426. centralizedThreadLocal = new CentralizedThreadLocal<>(null);
  427. Assert.assertEquals(
  428. CentralizedThreadLocal.class.getName() + "@" +
  429. Integer.toHexString(centralizedThreadLocal.hashCode()),
  430. centralizedThreadLocal.toString());
  431. }
  432. }