View Javadoc

1   package com.atlassian.cache;
2   
3   import java.lang.management.ManagementFactory;
4   import java.lang.management.ThreadInfo;
5   import java.lang.management.ThreadMXBean;
6   import java.util.concurrent.atomic.AtomicReference;
7   
8   import javax.management.MXBean;
9   
10  import com.atlassian.fugue.Throwables;
11  
12  /**
13   * A test thread built especially for multi-threaded concurrency testing.
14   *
15   * @since v2.4.5
16   */
17  @SuppressWarnings ("ClassExplicitlyExtendsThread")
18  public abstract class TestThread extends Thread
19  {
20      private final AtomicReference<Throwable> caught = new AtomicReference<Throwable>();
21      private final AtomicReference<AssertionError> killed = new AtomicReference<AssertionError>();
22  
23      public TestThread(final String name)
24      {
25          super("TestThread[" + name + ']');
26          setUncaughtExceptionHandler(BETTER_STACK_TRACER);
27      }
28  
29      public void run()
30      {
31          try
32          {
33              go();
34          }
35          catch (Exception e)
36          {
37              caught.set(e);
38              throw Throwables.propagate(e, RuntimeException.class);
39          }
40          catch (Error err)
41          {
42              caught.set(err);
43              final AssertionError killer = killed.get();
44              if (killer != null)
45              {
46                  throw killer;
47              }
48              throw err;
49          }
50      }
51  
52      protected abstract void go() throws Exception;
53  
54      private void verify()
55      {
56          final Throwable cause = caught.get();
57          if (cause != null)
58          {
59              final AssertionError err = new AssertionError("Failure in " + this);
60              err.initCause(cause);
61              throw err;
62          }
63      }
64  
65      public static void runTest(TestThread... threads)
66      {
67          startAll(threads);
68          joinAll(threads);
69          verifyAll(threads);
70      }
71  
72      private static void startAll(TestThread[] threads)
73      {
74          for (TestThread thd : threads)
75          {
76              thd.start();
77          }
78      }
79  
80      private static void joinAll(TestThread[] threads)
81      {
82          final long deadline = System.currentTimeMillis() + 2 * Barrier.DEFAULT_TIMEOUT;
83          try
84          {
85              for (TestThread thd : threads)
86              {
87                  final long timeleft = deadline - System.currentTimeMillis();
88                  if (timeleft > 0L)
89                  {
90                      thd.join(timeleft);
91                  }
92                  else
93                  {
94                      thd.join(50L);
95                  }
96                  if (thd.isAlive())
97                  {
98                      kill(thd);
99                  }
100             }
101         }
102         catch (InterruptedException ie)
103         {
104             throw new AssertionError(ie);
105         }
106     }
107 
108     private static void kill(final TestThread thd)
109     {
110         final Error err = new AssertionError("Thread did not finish: " + thd);
111         ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(thd.getId(), Integer.MAX_VALUE);
112         if (info != null)
113         {
114             final AssertionError killer = new AssertionError("Killed");
115             killer.setStackTrace(info.getStackTrace());
116             killer.initCause(err);
117             thd.killed.set(killer);
118             thd.stop();
119         }
120         throw err;
121     }
122 
123     private static void verifyAll(TestThread[] threads)
124     {
125         for (TestThread thd : threads)
126         {
127             thd.verify();
128         }
129     }
130 
131 
132     static final Thread.UncaughtExceptionHandler BETTER_STACK_TRACER = new Thread.UncaughtExceptionHandler()
133     {
134         @Override
135         synchronized public void uncaughtException(final Thread t, final Throwable e)
136         {
137             System.err.println("=========================================");
138             System.err.println("Uncaught exception in thread: " + t);
139             e.printStackTrace(System.err);
140             System.err.println("-----------------------------------------");
141             System.err.println();
142         }
143     };
144 }