blob: 7459d0e66db53723c917807f73af59f3a464f89f [file] [log] [blame]
// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package sync;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Sync {
public static final int THREADS = 10;
public static final int ITERATIONS = 10;
private static final int INITIAL_SHARED_STATE = -1;
private static final long SLEEP = 10;
// Shared mutable state that is tested to be consistent
private static int sharedState = INITIAL_SHARED_STATE;
private static boolean shouldThrow = false;
// Copy of interface java.util.function.Consumer to make this test work without a Java 8 runtime
// library
public interface Consumer<T> {
void accept(T t);
}
public static void couldThrow(int index) {
if (shouldThrow) throw new RuntimeException();
// Copy shared state and trash it (we set our index).
int local = sharedState;
sharedState = index;
try {
Thread.sleep(SLEEP);
} catch (Throwable e) {
throw new RuntimeException(e);
}
// Restore the shared state if it is still valid.
if (sharedState == index) {
sharedState = local;
}
}
public static synchronized void staticSynchronized(int index) {
System.out.println("static");
couldThrow(index);
System.out.println("end");
}
public synchronized void instanceSynchronized(int index) {
System.out.println("instance");
couldThrow(index);
System.out.println("end");
}
public void manualSynchronized(int index) {
System.out.println("manual");
synchronized (this) {
couldThrow(index);
}
System.out.println("manual");
}
public synchronized void tryCatchSynchronized(int index) {
System.out.println("trycatch");
try {
couldThrow(index);
try {
couldThrow(index);
} finally {
System.out.println("end");
return;
}
} catch (RuntimeException e) {
System.out.println("caught & end");
return;
} catch (Throwable e) {
System.out.println("caught other");
}
System.out.println("end");
}
public static synchronized void throwStaticSynchronized() {
throw new RuntimeException();
}
public synchronized void throwInstanceSynchronized() {
throw new RuntimeException();
}
public static void run(ExecutorService service, final Consumer<Integer> fn)
throws ExecutionException, InterruptedException {
Future[] results = new Future[ITERATIONS];
for (int i = 0; i < ITERATIONS; ++i) {
final int index = i;
results[i] = service.submit(new Runnable() {
@Override
public void run() {
fn.accept(index);
}
});
}
for (Future result : results) {
result.get();
}
if (sharedState != INITIAL_SHARED_STATE) {
throw new RuntimeException("Synchronization error!");
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
shouldThrow = args.length > 100;
ExecutorService service = Executors.newFixedThreadPool(THREADS);
run(service, new Consumer<Integer>() {
@Override
public void accept(Integer index) {
Sync.staticSynchronized(index);
}
});
final Sync sync = new Sync();
run(service, new Consumer<Integer>() {
@Override
public void accept(Integer index) {
sync.instanceSynchronized(index);
}
});
run(service, new Consumer<Integer>() {
@Override
public void accept(Integer index) {
sync.manualSynchronized(index);
}
});
run(service, new Consumer<Integer>() {
@Override
public void accept(Integer index) {
sync.tryCatchSynchronized(index);
}
});
service.shutdown();
service.awaitTermination(5, TimeUnit.SECONDS);
try {
Sync.throwStaticSynchronized();
throw new Error("expected throw");
} catch (RuntimeException e) {
System.out.println("caught throw");
}
try {
sync.throwInstanceSynchronized();
throw new Error("expected throw");
} catch (RuntimeException e) {
System.out.println("caught throw");
}
}
}