| // 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"); |
| } |
| } |
| } |