From f6ea6733b06809740a3a0dc651335a1635f7ff63 Mon Sep 17 00:00:00 2001
From: Kweku Adams
This structure is NOT thread-safe.
*/ public final class ArrayMapThis structure is NOT thread-safe.
*/ public final class ArraySet+ * ArraySet is explicitly documented to be non-thread-safe, yet it's easy to accidentally screw + * this up; ArraySet should (in the spirit of the core Java collection types) make an effort to + * catch this and throw ConcurrentModificationException instead of crashing somewhere in its + * internals. + */ + @Test + public void testConcurrentModificationException() throws Exception { + final int testDurMs = 10_000; + System.out.println("Starting ArraySet concurrency test"); + new Thread(() -> { + int i = 0; + while (mSet != null) { + try { + mSet.add(String.format("key %d", i++)); + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "concurrent modification uncaught, causing indexing failure", e); + fail("Concurrent modification uncaught, causing indexing failure: " + e); + } catch (ClassCastException e) { + Log.e(TAG, "concurrent modification uncaught, causing cache corruption", e); + fail("Concurrent modification uncaught, causing cache corruption: " + e); + } catch (ConcurrentModificationException e) { + System.out.println("[successfully caught CME at put #" + i + + " size=" + (mSet == null ? "??" : String.valueOf(mSet.size())) + "]"); + if (i % 200 == 0) { + System.out.print("."); + } + } + } + }).start(); + for (int i = 0; i < (testDurMs / 100); i++) { + try { + if (mSet.size() % 4 == 0) { + mSet.clear(); + } + System.out.print("X"); + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "concurrent modification uncaught, causing indexing failure", e); + fail("Concurrent modification uncaught, causing indexing failure: " + e); + } catch (ClassCastException e) { + Log.e(TAG, "concurrent modification uncaught, causing cache corruption", e); + fail("Concurrent modification uncaught, causing cache corruption: " + e); + } catch (ConcurrentModificationException e) { + System.out.println( + "[successfully caught CME at clear #" + i + " size=" + mSet.size() + "]"); + } + } + } + + /** + * Check to make sure the same operations behave as expected in a single thread. + */ + @Test + public void testNonConcurrentAccesses() throws Exception { + for (int i = 0; i < 100000; i++) { + try { + mSet.add(String.format("key %d", i++)); + if (i % 200 == 0) { + System.out.print("."); + } + if (i % 500 == 0) { + mSet.clear(); + System.out.print("X"); + } + } catch (ConcurrentModificationException e) { + Log.e(TAG, "concurrent modification caught on single thread", e); + fail(); + } + } + } +}