diff --git a/android/guava-testlib/src/com/google/common/testing/TearDownStack.java b/android/guava-testlib/src/com/google/common/testing/TearDownStack.java index c22b54c40486..b16869865907 100644 --- a/android/guava-testlib/src/com/google/common/testing/TearDownStack.java +++ b/android/guava-testlib/src/com/google/common/testing/TearDownStack.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.errorprone.annotations.concurrent.GuardedBy; import java.util.ArrayList; @@ -40,7 +41,9 @@ public class TearDownStack implements TearDownAccepter { private static final Logger logger = Logger.getLogger(TearDownStack.class.getName()); - @GuardedBy("stack") + @VisibleForTesting final Object lock = new Object(); + + @GuardedBy("lock") final LinkedList stack = new LinkedList<>(); private final boolean suppressThrows; @@ -55,7 +58,7 @@ public TearDownStack(boolean suppressThrows) { @Override public final void addTearDown(TearDown tearDown) { - synchronized (stack) { + synchronized (lock) { stack.addFirst(checkNotNull(tearDown)); } } @@ -64,7 +67,7 @@ public final void addTearDown(TearDown tearDown) { public final void runTearDown() { List exceptions = new ArrayList<>(); List stackCopy; - synchronized (stack) { + synchronized (lock) { stackCopy = Lists.newArrayList(stack); stack.clear(); } diff --git a/android/guava-testlib/src/com/google/common/testing/TestLogHandler.java b/android/guava-testlib/src/com/google/common/testing/TestLogHandler.java index e481a2f19e9b..a08ed550c231 100644 --- a/android/guava-testlib/src/com/google/common/testing/TestLogHandler.java +++ b/android/guava-testlib/src/com/google/common/testing/TestLogHandler.java @@ -16,7 +16,6 @@ package com.google.common.testing; - import com.google.common.annotations.GwtCompatible; import java.util.ArrayList; import java.util.Collections; @@ -55,14 +54,18 @@ @GwtCompatible @ElementTypesAreNonnullByDefault public class TestLogHandler extends Handler { + private final Object lock = new Object(); + /** We will keep a private list of all logged records */ private final List list = new ArrayList<>(); /** Adds the most recently logged record to our list. */ @Override - public synchronized void publish(@Nullable LogRecord record) { - if (record != null) { - list.add(record); + public void publish(@Nullable LogRecord record) { + synchronized (lock) { + if (record != null) { + list.add(record); + } } } @@ -72,8 +75,10 @@ public void flush() {} @Override public void close() {} - public synchronized void clear() { - list.clear(); + public void clear() { + synchronized (lock) { + list.clear(); + } } /** Returns a snapshot of the logged records. */ @@ -84,8 +89,10 @@ public synchronized void clear() { * TODO(cpovirk): consider renaming this method to reflect that it takes a snapshot (and/or return * an ImmutableList) */ - public synchronized List getStoredLogRecords() { - List result = new ArrayList<>(list); - return Collections.unmodifiableList(result); + public List getStoredLogRecords() { + synchronized (lock) { + List result = new ArrayList<>(list); + return Collections.unmodifiableList(result); + } } } diff --git a/android/guava-testlib/test/com/google/common/testing/TearDownStackTest.java b/android/guava-testlib/test/com/google/common/testing/TearDownStackTest.java index 63e162f75ee9..369563e04755 100644 --- a/android/guava-testlib/test/com/google/common/testing/TearDownStackTest.java +++ b/android/guava-testlib/test/com/google/common/testing/TearDownStackTest.java @@ -117,7 +117,7 @@ private TearDownStack buildTearDownStack() { @Override public void tearDown() throws Exception { - synchronized (result.stack) { + synchronized (result.lock) { assertEquals( "The test should have cleared the stack (say, by virtue of running runTearDown)", 0, diff --git a/android/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java b/android/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java index e234b0f163d4..5192bb8297e5 100644 --- a/android/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java +++ b/android/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java @@ -134,6 +134,7 @@ public void testOrderingUnmodifiable() { assertOrderingReadOnly(Multimaps.unmodifiableMultimap(multimap)); } + @J2ktIncompatible // Synchronized public void testOrderingSynchronized() { Multimap multimap = initializeMultimap5(); assertOrderingReadOnly(Multimaps.synchronizedMultimap(multimap)); diff --git a/android/guava-tests/test/com/google/common/collect/MapsTest.java b/android/guava-tests/test/com/google/common/collect/MapsTest.java index 07657d350d6e..92d02944fd5c 100644 --- a/android/guava-tests/test/com/google/common/collect/MapsTest.java +++ b/android/guava-tests/test/com/google/common/collect/MapsTest.java @@ -1324,6 +1324,7 @@ public void testImmutableEntryNull() { } /** See {@link SynchronizedBiMapTest} for more tests. */ + @J2ktIncompatible // Synchronized public void testSynchronizedBiMap() { BiMap bimap = HashBiMap.create(); bimap.put("one", 1); diff --git a/android/guava-tests/test/com/google/common/collect/MultimapsTest.java b/android/guava-tests/test/com/google/common/collect/MultimapsTest.java index 2a66620ba75c..171f7a48687e 100644 --- a/android/guava-tests/test/com/google/common/collect/MultimapsTest.java +++ b/android/guava-tests/test/com/google/common/collect/MultimapsTest.java @@ -167,6 +167,7 @@ public void testSerializingUnmodifiableTreeMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedArrayListMultimap() { checkUnmodifiableMultimap( Multimaps.synchronizedListMultimap( @@ -187,6 +188,7 @@ public void testSerializingUnmodifiableSynchronizedArrayListMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedHashMultimap() { checkUnmodifiableMultimap( Multimaps.synchronizedSetMultimap( @@ -207,6 +209,7 @@ public void testSerializingUnmodifiableSynchronizedHashMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedTreeMultimap() { TreeMultimap delegate = TreeMultimap.create(Ordering.natural(), INT_COMPARATOR); @@ -932,11 +935,13 @@ public String transformEntry(String key, Integer value) { assertEquals("{a=[a1, a4, a4], b=[b6]}", transformed.toString()); } + @J2ktIncompatible // Synchronized public void testSynchronizedMultimapSampleCodeCompilation() { // Extra indirection for J2KT, to avoid error: not enough information to infer type variable K this.<@Nullable Object, @Nullable Object>genericTestSynchronizedMultimapSampleCodeCompilation(); } + @J2ktIncompatible // Synchronized private void genericTestSynchronizedMultimapSampleCodeCompilation() { K key = null; diff --git a/android/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java b/android/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java index 0e85a24bb295..54ed07152f5e 100644 --- a/android/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java +++ b/android/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java @@ -132,8 +132,6 @@ public boolean isEmpty() { return super.isEmpty(); } - /* Don't test iterator(); it may or may not hold the mutex. */ - @Override public boolean remove(@Nullable Object o) { assertTrue(Thread.holdsLock(mutex)); diff --git a/android/guava/src/com/google/common/base/Suppliers.java b/android/guava/src/com/google/common/base/Suppliers.java index 9ef29af08933..c7cc3d0e23bd 100644 --- a/android/guava/src/com/google/common/base/Suppliers.java +++ b/android/guava/src/com/google/common/base/Suppliers.java @@ -121,6 +121,9 @@ public String toString() { @VisibleForTesting static class MemoizingSupplier implements Supplier, Serializable { + private final Object lock = + new Integer(1); // something serializable + final Supplier delegate; transient volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs @@ -136,7 +139,7 @@ static class MemoizingSupplier implements Supplier implements Supplier { + private final Object lock = new Object(); + @SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object private static final Supplier SUCCESSFULLY_COMPUTED = () -> { @@ -181,7 +186,7 @@ static class NonSerializableMemoizingSupplier implem public T get() { // Because Supplier is read-heavy, we use the "double-checked locking" pattern. if (delegate != SUCCESSFULLY_COMPUTED) { - synchronized (this) { + synchronized (lock) { if (delegate != SUCCESSFULLY_COMPUTED) { T t = delegate.get(); value = t; @@ -272,6 +277,9 @@ public String toString() { @SuppressWarnings("GoodTime") // lots of violations static class ExpiringMemoizingSupplier implements Supplier, Serializable { + private final Object lock = + new Integer(1); // something serializable + final Supplier delegate; final long durationNanos; @CheckForNull transient volatile T value; @@ -295,7 +303,7 @@ public T get() { long nanos = expirationNanos; long now = System.nanoTime(); if (nanos == 0 || now - nanos >= 0) { - synchronized (this) { + synchronized (lock) { if (nanos == expirationNanos) { // recheck for lost race T t = delegate.get(); value = t; @@ -367,11 +375,13 @@ public String toString() { * Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling * it, making it thread-safe. */ + @J2ktIncompatible public static Supplier synchronizedSupplier( Supplier delegate) { return new ThreadSafeSupplier<>(delegate); } + @J2ktIncompatible private static class ThreadSafeSupplier implements Supplier, Serializable { final Supplier delegate; diff --git a/android/guava/src/com/google/common/collect/Maps.java b/android/guava/src/com/google/common/collect/Maps.java index 15c8c1ab8935..5ba7ff2b2283 100644 --- a/android/guava/src/com/google/common/collect/Maps.java +++ b/android/guava/src/com/google/common/collect/Maps.java @@ -1624,6 +1624,7 @@ public String toString() { * @param bimap the bimap to be wrapped in a synchronized view * @return a synchronized view of the specified bimap */ + @J2ktIncompatible // Synchronized public static BiMap synchronizedBiMap(BiMap bimap) { return Synchronized.biMap(bimap, null); @@ -3609,6 +3610,7 @@ public NavigableMap tailMap(@ParametricNullness K fromKey, boolean inclusi * @since 13.0 */ @GwtIncompatible // NavigableMap + @J2ktIncompatible // Synchronized public static NavigableMap synchronizedNavigableMap(NavigableMap navigableMap) { return Synchronized.navigableMap(navigableMap); diff --git a/android/guava/src/com/google/common/collect/Multimaps.java b/android/guava/src/com/google/common/collect/Multimaps.java index d5c027fbfa1f..441c6c2d0089 100644 --- a/android/guava/src/com/google/common/collect/Multimaps.java +++ b/android/guava/src/com/google/common/collect/Multimaps.java @@ -639,6 +639,7 @@ M invertFrom(Multimap source, M dest) { * @param multimap the multimap to be wrapped in a synchronized view * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static Multimap synchronizedMultimap(Multimap multimap) { return Synchronized.multimap(multimap, null); @@ -899,6 +900,7 @@ public Comparator valueComparator() { * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static SetMultimap synchronizedSetMultimap(SetMultimap multimap) { return Synchronized.setMultimap(multimap, null); @@ -946,6 +948,7 @@ public static SetMultimap unmodifiableSetMultimap( * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static SortedSetMultimap synchronizedSortedSetMultimap(SortedSetMultimap multimap) { return Synchronized.sortedSetMultimap(multimap, null); @@ -978,6 +981,7 @@ SortedSetMultimap unmodifiableSortedSetMultimap(SortedSetMultimap de * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static ListMultimap synchronizedListMultimap(ListMultimap multimap) { return Synchronized.listMultimap(multimap, null); diff --git a/android/guava/src/com/google/common/collect/Queues.java b/android/guava/src/com/google/common/collect/Queues.java index 4525f2623897..3f5d9b6ff520 100644 --- a/android/guava/src/com/google/common/collect/Queues.java +++ b/android/guava/src/com/google/common/collect/Queues.java @@ -407,6 +407,7 @@ public static int drainUninterruptibly( * @return a synchronized view of the specified queue * @since 14.0 */ + @J2ktIncompatible // Synchronized public static Queue synchronizedQueue(Queue queue) { return Synchronized.queue(queue, null); } @@ -440,6 +441,7 @@ public static int drainUninterruptibly( * @return a synchronized view of the specified deque * @since 15.0 */ + @J2ktIncompatible // Synchronized public static Deque synchronizedDeque(Deque deque) { return Synchronized.deque(deque, null); } diff --git a/android/guava/src/com/google/common/collect/Sets.java b/android/guava/src/com/google/common/collect/Sets.java index 943e71957d64..0cecc57cf84a 100644 --- a/android/guava/src/com/google/common/collect/Sets.java +++ b/android/guava/src/com/google/common/collect/Sets.java @@ -1923,6 +1923,7 @@ public NavigableSet tailSet(@ParametricNullness E fromElement, boolean inclus * @since 13.0 */ @GwtIncompatible // NavigableSet + @J2ktIncompatible // Synchronized public static NavigableSet synchronizedNavigableSet( NavigableSet navigableSet) { return Synchronized.navigableSet(navigableSet); diff --git a/android/guava/src/com/google/common/collect/Synchronized.java b/android/guava/src/com/google/common/collect/Synchronized.java index adb94fd03461..dcf409d42b03 100644 --- a/android/guava/src/com/google/common/collect/Synchronized.java +++ b/android/guava/src/com/google/common/collect/Synchronized.java @@ -55,6 +55,7 @@ * @author Mike Bostock * @author Jared Levy */ +@J2ktIncompatible @GwtCompatible(emulated = true) @ElementTypesAreNonnullByDefault /* diff --git a/android/guava/src/com/google/common/collect/Tables.java b/android/guava/src/com/google/common/collect/Tables.java index 789a57e1e2c5..69fe5897e4c3 100644 --- a/android/guava/src/com/google/common/collect/Tables.java +++ b/android/guava/src/com/google/common/collect/Tables.java @@ -21,6 +21,7 @@ import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT; import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.J2ktIncompatible; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Supplier; @@ -730,6 +731,7 @@ public Map apply(Map input) { * @return a synchronized view of the specified table * @since 22.0 */ + @J2ktIncompatible // Synchronized public static Table synchronizedTable(Table table) { return Synchronized.table(table, null); diff --git a/android/guava/src/com/google/common/util/concurrent/LazyLogger.java b/android/guava/src/com/google/common/util/concurrent/LazyLogger.java index 9ae0f784e57e..ef1b56957d52 100644 --- a/android/guava/src/com/google/common/util/concurrent/LazyLogger.java +++ b/android/guava/src/com/google/common/util/concurrent/LazyLogger.java @@ -22,6 +22,8 @@ @GwtCompatible @ElementTypesAreNonnullByDefault final class LazyLogger { + private final Object lock = new Object(); + private final String loggerName; private volatile @Nullable Logger logger; @@ -45,7 +47,7 @@ Logger get() { if (local != null) { return local; } - synchronized (this) { + synchronized (lock) { local = logger; if (local != null) { return local; diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionSpliteratorTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionSpliteratorTester.java index a4ee0b56a4fa..45fa49a82f53 100644 --- a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionSpliteratorTester.java +++ b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionSpliteratorTester.java @@ -46,41 +46,31 @@ public class CollectionSpliteratorTester extends AbstractCollectionTester @CollectionFeature.Require(absent = KNOWN_ORDER) public void testSpliteratorUnknownOrder() { - synchronized (collection) { - SpliteratorTester.of(collection::spliterator).expect(getSampleElements()); - } + SpliteratorTester.of(collection::spliterator).expect(getSampleElements()); } @CollectionFeature.Require(KNOWN_ORDER) public void testSpliteratorKnownOrder() { - synchronized (collection) { - SpliteratorTester.of(collection::spliterator).expect(getOrderedElements()).inOrder(); - } + SpliteratorTester.of(collection::spliterator).expect(getOrderedElements()).inOrder(); } @CollectionFeature.Require(ALLOWS_NULL_VALUES) @CollectionSize.Require(absent = ZERO) public void testSpliteratorNullable() { initCollectionWithNullElement(); - synchronized (collection) { // for Collections.synchronized - assertFalse(collection.spliterator().hasCharacteristics(Spliterator.NONNULL)); - } + assertFalse(collection.spliterator().hasCharacteristics(Spliterator.NONNULL)); } @CollectionFeature.Require(SUPPORTS_ADD) public void testSpliteratorNotImmutable_CollectionAllowsAdd() { // If add is supported, verify that IMMUTABLE is not reported. - synchronized (collection) { // for Collections.synchronized - assertFalse(collection.spliterator().hasCharacteristics(Spliterator.IMMUTABLE)); - } + assertFalse(collection.spliterator().hasCharacteristics(Spliterator.IMMUTABLE)); } @CollectionFeature.Require(SUPPORTS_REMOVE) public void testSpliteratorNotImmutable_CollectionAllowsRemove() { // If remove is supported, verify that IMMUTABLE is not reported. - synchronized (collection) { // for Collections.synchronized - assertFalse(collection.spliterator().hasCharacteristics(Spliterator.IMMUTABLE)); - } + assertFalse(collection.spliterator().hasCharacteristics(Spliterator.IMMUTABLE)); } @J2ktIncompatible diff --git a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionStreamTester.java b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionStreamTester.java index 38bbb90a0900..2cf0e7236506 100644 --- a/guava-testlib/src/com/google/common/collect/testing/testers/CollectionStreamTester.java +++ b/guava-testlib/src/com/google/common/collect/testing/testers/CollectionStreamTester.java @@ -41,22 +41,16 @@ public class CollectionStreamTester extends AbstractCollectionTester { @CollectionFeature.Require(absent = KNOWN_ORDER) public void testStreamToArrayUnknownOrder() { - synchronized (collection) { // to allow Collections.synchronized* tests to pass - Helpers.assertEqualIgnoringOrder( - getSampleElements(), Arrays.asList(collection.stream().toArray())); - } + Helpers.assertEqualIgnoringOrder( + getSampleElements(), Arrays.asList(collection.stream().toArray())); } @CollectionFeature.Require(KNOWN_ORDER) public void testStreamToArrayKnownOrder() { - synchronized (collection) { // to allow Collections.synchronized* tests to pass - assertEquals(getOrderedElements(), Arrays.asList(collection.stream().toArray())); - } + assertEquals(getOrderedElements(), Arrays.asList(collection.stream().toArray())); } public void testStreamCount() { - synchronized (collection) { // to allow Collections.synchronized* tests to pass - assertEquals(getNumElements(), collection.stream().count()); - } + assertEquals(getNumElements(), collection.stream().count()); } } diff --git a/guava-testlib/src/com/google/common/testing/TearDownStack.java b/guava-testlib/src/com/google/common/testing/TearDownStack.java index c22b54c40486..b16869865907 100644 --- a/guava-testlib/src/com/google/common/testing/TearDownStack.java +++ b/guava-testlib/src/com/google/common/testing/TearDownStack.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.errorprone.annotations.concurrent.GuardedBy; import java.util.ArrayList; @@ -40,7 +41,9 @@ public class TearDownStack implements TearDownAccepter { private static final Logger logger = Logger.getLogger(TearDownStack.class.getName()); - @GuardedBy("stack") + @VisibleForTesting final Object lock = new Object(); + + @GuardedBy("lock") final LinkedList stack = new LinkedList<>(); private final boolean suppressThrows; @@ -55,7 +58,7 @@ public TearDownStack(boolean suppressThrows) { @Override public final void addTearDown(TearDown tearDown) { - synchronized (stack) { + synchronized (lock) { stack.addFirst(checkNotNull(tearDown)); } } @@ -64,7 +67,7 @@ public final void addTearDown(TearDown tearDown) { public final void runTearDown() { List exceptions = new ArrayList<>(); List stackCopy; - synchronized (stack) { + synchronized (lock) { stackCopy = Lists.newArrayList(stack); stack.clear(); } diff --git a/guava-testlib/src/com/google/common/testing/TestLogHandler.java b/guava-testlib/src/com/google/common/testing/TestLogHandler.java index e481a2f19e9b..a08ed550c231 100644 --- a/guava-testlib/src/com/google/common/testing/TestLogHandler.java +++ b/guava-testlib/src/com/google/common/testing/TestLogHandler.java @@ -16,7 +16,6 @@ package com.google.common.testing; - import com.google.common.annotations.GwtCompatible; import java.util.ArrayList; import java.util.Collections; @@ -55,14 +54,18 @@ @GwtCompatible @ElementTypesAreNonnullByDefault public class TestLogHandler extends Handler { + private final Object lock = new Object(); + /** We will keep a private list of all logged records */ private final List list = new ArrayList<>(); /** Adds the most recently logged record to our list. */ @Override - public synchronized void publish(@Nullable LogRecord record) { - if (record != null) { - list.add(record); + public void publish(@Nullable LogRecord record) { + synchronized (lock) { + if (record != null) { + list.add(record); + } } } @@ -72,8 +75,10 @@ public void flush() {} @Override public void close() {} - public synchronized void clear() { - list.clear(); + public void clear() { + synchronized (lock) { + list.clear(); + } } /** Returns a snapshot of the logged records. */ @@ -84,8 +89,10 @@ public synchronized void clear() { * TODO(cpovirk): consider renaming this method to reflect that it takes a snapshot (and/or return * an ImmutableList) */ - public synchronized List getStoredLogRecords() { - List result = new ArrayList<>(list); - return Collections.unmodifiableList(result); + public List getStoredLogRecords() { + synchronized (lock) { + List result = new ArrayList<>(list); + return Collections.unmodifiableList(result); + } } } diff --git a/guava-testlib/test/com/google/common/testing/TearDownStackTest.java b/guava-testlib/test/com/google/common/testing/TearDownStackTest.java index 63e162f75ee9..369563e04755 100644 --- a/guava-testlib/test/com/google/common/testing/TearDownStackTest.java +++ b/guava-testlib/test/com/google/common/testing/TearDownStackTest.java @@ -117,7 +117,7 @@ private TearDownStack buildTearDownStack() { @Override public void tearDown() throws Exception { - synchronized (result.stack) { + synchronized (result.lock) { assertEquals( "The test should have cleared the stack (say, by virtue of running runTearDown)", 0, diff --git a/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java b/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java index 625e1892c992..1a1382bd801b 100644 --- a/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java +++ b/guava-tests/test/com/google/common/collect/LinkedHashMultimapTest.java @@ -135,6 +135,7 @@ public void testOrderingUnmodifiable() { assertOrderingReadOnly(Multimaps.unmodifiableMultimap(multimap)); } + @J2ktIncompatible // Synchronized public void testOrderingSynchronized() { Multimap multimap = initializeMultimap5(); assertOrderingReadOnly(Multimaps.synchronizedMultimap(multimap)); diff --git a/guava-tests/test/com/google/common/collect/MapsTest.java b/guava-tests/test/com/google/common/collect/MapsTest.java index ac9bcc2b078b..31cdee432fde 100644 --- a/guava-tests/test/com/google/common/collect/MapsTest.java +++ b/guava-tests/test/com/google/common/collect/MapsTest.java @@ -1369,6 +1369,7 @@ public void testImmutableEntryNull() { } /** See {@link SynchronizedBiMapTest} for more tests. */ + @J2ktIncompatible // Synchronized public void testSynchronizedBiMap() { BiMap bimap = HashBiMap.create(); bimap.put("one", 1); diff --git a/guava-tests/test/com/google/common/collect/MultimapsTest.java b/guava-tests/test/com/google/common/collect/MultimapsTest.java index a821d77d5052..3e79c97d99da 100644 --- a/guava-tests/test/com/google/common/collect/MultimapsTest.java +++ b/guava-tests/test/com/google/common/collect/MultimapsTest.java @@ -236,6 +236,7 @@ public void testSerializingUnmodifiableTreeMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedArrayListMultimap() { checkUnmodifiableMultimap( Multimaps.synchronizedListMultimap( @@ -256,6 +257,7 @@ public void testSerializingUnmodifiableSynchronizedArrayListMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedHashMultimap() { checkUnmodifiableMultimap( Multimaps.synchronizedSetMultimap( @@ -276,6 +278,7 @@ public void testSerializingUnmodifiableSynchronizedHashMultimap() { } @GwtIncompatible // slow (~10s) + @J2ktIncompatible // Synchronized public void testUnmodifiableSynchronizedTreeMultimap() { TreeMultimap delegate = TreeMultimap.create(Ordering.natural(), INT_COMPARATOR); @@ -1001,11 +1004,13 @@ public String transformEntry(String key, Integer value) { assertEquals("{a=[a1, a4, a4], b=[b6]}", transformed.toString()); } + @J2ktIncompatible // Synchronized public void testSynchronizedMultimapSampleCodeCompilation() { // Extra indirection for J2KT, to avoid error: not enough information to infer type variable K this.<@Nullable Object, @Nullable Object>genericTestSynchronizedMultimapSampleCodeCompilation(); } + @J2ktIncompatible // Synchronized private void genericTestSynchronizedMultimapSampleCodeCompilation() { K key = null; diff --git a/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java b/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java index 9db478cbb0be..1c42b92a7c08 100644 --- a/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java +++ b/guava-tests/test/com/google/common/collect/SynchronizedSetTest.java @@ -25,6 +25,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.Spliterator; +import java.util.stream.Stream; import junit.framework.Test; import junit.framework.TestCase; import org.checkerframework.checker.nullness.qual.Nullable; @@ -130,7 +132,32 @@ public boolean isEmpty() { return super.isEmpty(); } - /* Don't test iterator(); it may or may not hold the mutex. */ + /* + * We don't assert that the lock is held during calls to iterator(), stream(), and spliterator: + * `Synchronized` doesn't guarantee that it will hold the mutex for those calls because callers + * are responsible for taking the mutex themselves: + * https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/util/Collections.html#synchronizedCollection(java.util.Collection) + * + * Similarly, we avoid having those methods *implemented* in terms of *other* TestSet methods + * that will perform holdsLock assertions: + * + * - For iterator(), we can accomplish that by not overriding iterator() at all. That way, we + * inherit an implementation that forwards to the delegate collection, which performs no + * holdsLock assertions. + * + * - For stream() and spliterator(), we have to forward to the delegate ourselves because + * ForwardingSet does not forward `default` methods, as discussed in its Javadoc. + */ + + @Override + public Stream stream() { + return delegate.stream(); + } + + @Override + public Spliterator spliterator() { + return delegate.spliterator(); + } @Override public boolean remove(@Nullable Object o) { diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java index 9ef29af08933..c7cc3d0e23bd 100644 --- a/guava/src/com/google/common/base/Suppliers.java +++ b/guava/src/com/google/common/base/Suppliers.java @@ -121,6 +121,9 @@ public String toString() { @VisibleForTesting static class MemoizingSupplier implements Supplier, Serializable { + private final Object lock = + new Integer(1); // something serializable + final Supplier delegate; transient volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs @@ -136,7 +139,7 @@ static class MemoizingSupplier implements Supplier implements Supplier { + private final Object lock = new Object(); + @SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object private static final Supplier SUCCESSFULLY_COMPUTED = () -> { @@ -181,7 +186,7 @@ static class NonSerializableMemoizingSupplier implem public T get() { // Because Supplier is read-heavy, we use the "double-checked locking" pattern. if (delegate != SUCCESSFULLY_COMPUTED) { - synchronized (this) { + synchronized (lock) { if (delegate != SUCCESSFULLY_COMPUTED) { T t = delegate.get(); value = t; @@ -272,6 +277,9 @@ public String toString() { @SuppressWarnings("GoodTime") // lots of violations static class ExpiringMemoizingSupplier implements Supplier, Serializable { + private final Object lock = + new Integer(1); // something serializable + final Supplier delegate; final long durationNanos; @CheckForNull transient volatile T value; @@ -295,7 +303,7 @@ public T get() { long nanos = expirationNanos; long now = System.nanoTime(); if (nanos == 0 || now - nanos >= 0) { - synchronized (this) { + synchronized (lock) { if (nanos == expirationNanos) { // recheck for lost race T t = delegate.get(); value = t; @@ -367,11 +375,13 @@ public String toString() { * Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling * it, making it thread-safe. */ + @J2ktIncompatible public static Supplier synchronizedSupplier( Supplier delegate) { return new ThreadSafeSupplier<>(delegate); } + @J2ktIncompatible private static class ThreadSafeSupplier implements Supplier, Serializable { final Supplier delegate; diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java index 0876c9a7b0b7..2622db163a80 100644 --- a/guava/src/com/google/common/collect/Maps.java +++ b/guava/src/com/google/common/collect/Maps.java @@ -1654,6 +1654,7 @@ public String toString() { * @param bimap the bimap to be wrapped in a synchronized view * @return a synchronized view of the specified bimap */ + @J2ktIncompatible // Synchronized public static BiMap synchronizedBiMap(BiMap bimap) { return Synchronized.biMap(bimap, null); @@ -3799,6 +3800,7 @@ public NavigableMap tailMap(@ParametricNullness K fromKey, boolean inclusi * @since 13.0 */ @GwtIncompatible // NavigableMap + @J2ktIncompatible // Synchronized public static NavigableMap synchronizedNavigableMap(NavigableMap navigableMap) { return Synchronized.navigableMap(navigableMap); diff --git a/guava/src/com/google/common/collect/Multimaps.java b/guava/src/com/google/common/collect/Multimaps.java index 58d727010d75..c0aaa2cba375 100644 --- a/guava/src/com/google/common/collect/Multimaps.java +++ b/guava/src/com/google/common/collect/Multimaps.java @@ -638,6 +638,7 @@ M invertFrom(Multimap source, M dest) { * @param multimap the multimap to be wrapped in a synchronized view * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static Multimap synchronizedMultimap(Multimap multimap) { return Synchronized.multimap(multimap, null); @@ -903,6 +904,7 @@ public Comparator valueComparator() { * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static SetMultimap synchronizedSetMultimap(SetMultimap multimap) { return Synchronized.setMultimap(multimap, null); @@ -950,6 +952,7 @@ public static SetMultimap unmodifiableSetMultimap( * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static SortedSetMultimap synchronizedSortedSetMultimap(SortedSetMultimap multimap) { return Synchronized.sortedSetMultimap(multimap, null); @@ -982,6 +985,7 @@ SortedSetMultimap unmodifiableSortedSetMultimap(SortedSetMultimap de * @param multimap the multimap to be wrapped * @return a synchronized view of the specified multimap */ + @J2ktIncompatible // Synchronized public static ListMultimap synchronizedListMultimap(ListMultimap multimap) { return Synchronized.listMultimap(multimap, null); diff --git a/guava/src/com/google/common/collect/Queues.java b/guava/src/com/google/common/collect/Queues.java index e6cf8d6e30e5..253c9052b5fd 100644 --- a/guava/src/com/google/common/collect/Queues.java +++ b/guava/src/com/google/common/collect/Queues.java @@ -452,6 +452,7 @@ public static int drainUninterruptibly( * @return a synchronized view of the specified queue * @since 14.0 */ + @J2ktIncompatible // Synchronized public static Queue synchronizedQueue(Queue queue) { return Synchronized.queue(queue, null); } @@ -485,6 +486,7 @@ public static int drainUninterruptibly( * @return a synchronized view of the specified deque * @since 15.0 */ + @J2ktIncompatible // Synchronized public static Deque synchronizedDeque(Deque deque) { return Synchronized.deque(deque, null); } diff --git a/guava/src/com/google/common/collect/Sets.java b/guava/src/com/google/common/collect/Sets.java index 386633f977a8..d46bc06715b3 100644 --- a/guava/src/com/google/common/collect/Sets.java +++ b/guava/src/com/google/common/collect/Sets.java @@ -1989,6 +1989,7 @@ public NavigableSet tailSet(@ParametricNullness E fromElement, boolean inclus * @since 13.0 */ @GwtIncompatible // NavigableSet + @J2ktIncompatible // Synchronized public static NavigableSet synchronizedNavigableSet( NavigableSet navigableSet) { return Synchronized.navigableSet(navigableSet); diff --git a/guava/src/com/google/common/collect/Synchronized.java b/guava/src/com/google/common/collect/Synchronized.java index 26fbd034dad0..b3972cfd096f 100644 --- a/guava/src/com/google/common/collect/Synchronized.java +++ b/guava/src/com/google/common/collect/Synchronized.java @@ -64,6 +64,7 @@ * @author Mike Bostock * @author Jared Levy */ +@J2ktIncompatible @GwtCompatible(emulated = true) @ElementTypesAreNonnullByDefault /* diff --git a/guava/src/com/google/common/collect/Tables.java b/guava/src/com/google/common/collect/Tables.java index d8aabde00ab3..a55d691014f3 100644 --- a/guava/src/com/google/common/collect/Tables.java +++ b/guava/src/com/google/common/collect/Tables.java @@ -21,6 +21,7 @@ import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT; import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.J2ktIncompatible; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Supplier; @@ -737,6 +738,7 @@ public Map apply(Map input) { * @return a synchronized view of the specified table * @since 22.0 */ + @J2ktIncompatible // Synchronized public static Table synchronizedTable(Table table) { return Synchronized.table(table, null); diff --git a/guava/src/com/google/common/util/concurrent/LazyLogger.java b/guava/src/com/google/common/util/concurrent/LazyLogger.java index 9ae0f784e57e..ef1b56957d52 100644 --- a/guava/src/com/google/common/util/concurrent/LazyLogger.java +++ b/guava/src/com/google/common/util/concurrent/LazyLogger.java @@ -22,6 +22,8 @@ @GwtCompatible @ElementTypesAreNonnullByDefault final class LazyLogger { + private final Object lock = new Object(); + private final String loggerName; private volatile @Nullable Logger logger; @@ -45,7 +47,7 @@ Logger get() { if (local != null) { return local; } - synchronized (this) { + synchronized (lock) { local = logger; if (local != null) { return local;