Java

Форк
0
/
GcFinalizationTest.java 
238 строк · 7.7 Кб
1
/*
2
 * Copyright (C) 2011 The Guava Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.google.common.testing;
18

19
import static com.google.common.truth.Truth.assertThat;
20
import static org.junit.Assert.assertThrows;
21

22
import com.google.common.testing.GcFinalization.FinalizationPredicate;
23
import com.google.common.util.concurrent.SettableFuture;
24
import java.lang.ref.WeakReference;
25
import java.util.WeakHashMap;
26
import java.util.concurrent.CountDownLatch;
27
import java.util.concurrent.atomic.AtomicBoolean;
28
import junit.framework.TestCase;
29
import org.checkerframework.checker.nullness.qual.Nullable;
30

31
/**
32
 * Tests for {@link GcFinalization}.
33
 *
34
 * @author Martin Buchholz
35
 * @author mike nonemacher
36
 */
37
@AndroidIncompatible // depends on details of gc
38

39
public class GcFinalizationTest extends TestCase {
40

41
  // ----------------------------------------------------------------
42
  // Ordinary tests of successful method execution
43
  // ----------------------------------------------------------------
44

45
  public void testAwait_countDownLatch() {
46
    final CountDownLatch latch = new CountDownLatch(1);
47
    Object unused =
48
        new Object() {
49
          @SuppressWarnings({"removal", "Finalize"}) // b/260137033
50
          @Override
51
          protected void finalize() {
52
            latch.countDown();
53
          }
54
        };
55
    unused = null; // Hint to the JIT that unused is unreachable
56
    GcFinalization.await(latch);
57
    assertEquals(0, latch.getCount());
58
  }
59

60
  public void testAwaitDone_future() {
61
    final SettableFuture<@Nullable Void> future = SettableFuture.create();
62
    Object unused =
63
        new Object() {
64
          @SuppressWarnings({"removal", "Finalize"}) // b/260137033
65
          @Override
66
          protected void finalize() {
67
            future.set(null);
68
          }
69
        };
70
    unused = null; // Hint to the JIT that unused is unreachable
71
    GcFinalization.awaitDone(future);
72
    assertTrue(future.isDone());
73
    assertFalse(future.isCancelled());
74
  }
75

76
  public void testAwaitDone_future_cancel() {
77
    final SettableFuture<@Nullable Void> future = SettableFuture.create();
78
    Object unused =
79
        new Object() {
80
          @SuppressWarnings({"removal", "Finalize"}) // b/260137033
81
          @Override
82
          protected void finalize() {
83
            future.cancel(false);
84
          }
85
        };
86
    unused = null; // Hint to the JIT that unused is unreachable
87
    GcFinalization.awaitDone(future);
88
    assertTrue(future.isDone());
89
    assertTrue(future.isCancelled());
90
  }
91

92
  public void testAwaitClear() {
93
    final WeakReference<Object> ref = new WeakReference<>(new Object());
94
    GcFinalization.awaitClear(ref);
95
    assertNull(ref.get());
96
  }
97

98
  public void testAwaitDone_finalizationPredicate() {
99
    final WeakHashMap<Object, Object> map = new WeakHashMap<>();
100
    map.put(new Object(), Boolean.TRUE);
101
    GcFinalization.awaitDone(
102
        new FinalizationPredicate() {
103
          @Override
104
          public boolean isDone() {
105
            return map.isEmpty();
106
          }
107
        });
108
    assertTrue(map.isEmpty());
109
  }
110

111
  // ----------------------------------------------------------------
112
  // Test that interrupts result in RuntimeException, not InterruptedException.
113
  // Trickier than it looks, because runFinalization swallows interrupts.
114
  // ----------------------------------------------------------------
115

116
  class Interruptenator extends Thread {
117
    final AtomicBoolean shutdown;
118

119
    Interruptenator(final Thread interruptee) {
120
      this(interruptee, new AtomicBoolean(false));
121
    }
122

123
    Interruptenator(final Thread interruptee, final AtomicBoolean shutdown) {
124
      super(
125
          new Runnable() {
126
            @Override
127
            public void run() {
128
              while (!shutdown.get()) {
129
                interruptee.interrupt();
130
                Thread.yield();
131
              }
132
            }
133
          });
134
      this.shutdown = shutdown;
135
      start();
136
    }
137

138
    void shutdown() {
139
      shutdown.set(true);
140
      while (this.isAlive()) {
141
        Thread.yield();
142
      }
143
    }
144
  }
145

146
  void assertWrapsInterruptedException(RuntimeException e) {
147
    assertThat(e).hasMessageThat().contains("Unexpected interrupt");
148
    assertThat(e).hasCauseThat().isInstanceOf(InterruptedException.class);
149
  }
150

151
  public void testAwait_countDownLatch_interrupted() {
152
    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
153
    try {
154
      final CountDownLatch latch = new CountDownLatch(1);
155
      RuntimeException expected =
156
          assertThrows(RuntimeException.class, () -> GcFinalization.await(latch));
157
      assertWrapsInterruptedException(expected);
158
    } finally {
159
      interruptenator.shutdown();
160
      Thread.interrupted();
161
    }
162
  }
163

164
  public void testAwaitDone_future_interrupted_interrupted() {
165
    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
166
    try {
167
      final SettableFuture<@Nullable Void> future = SettableFuture.create();
168
      RuntimeException expected =
169
          assertThrows(RuntimeException.class, () -> GcFinalization.awaitDone(future));
170
      assertWrapsInterruptedException(expected);
171
    } finally {
172
      interruptenator.shutdown();
173
      Thread.interrupted();
174
    }
175
  }
176

177
  public void testAwaitClear_interrupted() {
178
    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
179
    try {
180
      final WeakReference<Object> ref = new WeakReference<Object>(Boolean.TRUE);
181
      RuntimeException expected =
182
          assertThrows(RuntimeException.class, () -> GcFinalization.awaitClear(ref));
183
      assertWrapsInterruptedException(expected);
184
    } finally {
185
      interruptenator.shutdown();
186
      Thread.interrupted();
187
    }
188
  }
189

190
  public void testAwaitDone_finalizationPredicate_interrupted() {
191
    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
192
    try {
193
      RuntimeException expected =
194
          assertThrows(
195
              RuntimeException.class,
196
              () ->
197
                  GcFinalization.awaitDone(
198
                      new FinalizationPredicate() {
199
                        @Override
200
                        public boolean isDone() {
201
                          return false;
202
                        }
203
                      }));
204
      assertWrapsInterruptedException(expected);
205
    } finally {
206
      interruptenator.shutdown();
207
      Thread.interrupted();
208
    }
209
  }
210

211
  /**
212
   * awaitFullGc() is not quite as reliable a way to ensure calling of a specific finalize method as
213
   * the more direct await* methods, but should be reliable enough in practice to avoid flakiness of
214
   * this test. (And if it isn't, we'd like to know about it first!)
215
   */
216
  public void testAwaitFullGc() {
217
    final CountDownLatch finalizerRan = new CountDownLatch(1);
218
    final WeakReference<Object> ref =
219
        new WeakReference<Object>(
220
            new Object() {
221
              @SuppressWarnings({"removal", "Finalize"}) // b/260137033
222
              @Override
223
              protected void finalize() {
224
                finalizerRan.countDown();
225
              }
226
            });
227

228
    // Don't copy this into your own test!
229
    // Use e.g. awaitClear or await(CountDownLatch) instead.
230
    GcFinalization.awaitFullGc();
231

232
    // If this test turns out to be flaky, add a second call to awaitFullGc()
233
    // GcFinalization.awaitFullGc();
234

235
    assertEquals(0, finalizerRan.getCount());
236
    assertNull(ref.get());
237
  }
238
}
239

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.