15 |
|
import java.io.ObjectOutputStream; |
16 |
|
import java.lang.management.ManagementFactory; |
17 |
|
import java.lang.management.ThreadInfo; |
18 |
+ |
import java.lang.management.ThreadMXBean; |
19 |
|
import java.lang.reflect.Constructor; |
20 |
|
import java.lang.reflect.Method; |
21 |
|
import java.lang.reflect.Modifier; |
519 |
|
* the same test have no effect. |
520 |
|
*/ |
521 |
|
public void threadRecordFailure(Throwable t) { |
522 |
+ |
printAllStackTraces(); |
523 |
|
threadFailure.compareAndSet(null, t); |
524 |
|
} |
525 |
|
|
599 |
|
fail(reason); |
600 |
|
} catch (AssertionFailedError t) { |
601 |
|
threadRecordFailure(t); |
602 |
< |
fail(reason); |
602 |
> |
throw t; |
603 |
|
} |
604 |
|
} |
605 |
|
|
745 |
|
} |
746 |
|
|
747 |
|
/** |
748 |
+ |
* Allows use of try-with-resources with per-test thread pools. |
749 |
+ |
*/ |
750 |
+ |
static class PoolCloser<T extends ExecutorService> |
751 |
+ |
implements AutoCloseable { |
752 |
+ |
public final T pool; |
753 |
+ |
public PoolCloser(T pool) { this.pool = pool; } |
754 |
+ |
public void close() { joinPool(pool); } |
755 |
+ |
} |
756 |
+ |
|
757 |
+ |
/** |
758 |
|
* Waits out termination of a thread pool or fails doing so. |
759 |
|
*/ |
760 |
< |
void joinPool(ExecutorService pool) { |
760 |
> |
static void joinPool(ExecutorService pool) { |
761 |
|
try { |
762 |
|
pool.shutdown(); |
763 |
|
if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)) |
779 |
|
* necessarily individually slow because they must block. |
780 |
|
*/ |
781 |
|
void testInParallel(Action ... actions) { |
782 |
< |
ExecutorService pool = Executors.newCachedThreadPool(); |
783 |
< |
try { |
782 |
> |
try (PoolCloser<ExecutorService> poolCloser |
783 |
> |
= new PoolCloser<>(Executors.newCachedThreadPool())) { |
784 |
> |
ExecutorService pool = poolCloser.pool; |
785 |
|
ArrayList<Future<?>> futures = new ArrayList<>(actions.length); |
786 |
|
for (final Action action : actions) |
787 |
|
futures.add(pool.submit(new CheckedRunnable() { |
794 |
|
} catch (Exception ex) { |
795 |
|
threadUnexpectedException(ex); |
796 |
|
} |
784 |
– |
} finally { |
785 |
– |
joinPool(pool); |
797 |
|
} |
798 |
|
} |
799 |
|
|
800 |
|
/** |
801 |
|
* A debugging tool to print all stack traces, as jstack does. |
802 |
+ |
* Uninteresting threads are filtered out. |
803 |
|
*/ |
804 |
|
static void printAllStackTraces() { |
805 |
< |
for (ThreadInfo info : |
806 |
< |
ManagementFactory.getThreadMXBean() |
807 |
< |
.dumpAllThreads(true, true)) |
805 |
> |
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); |
806 |
> |
System.err.println("------ stacktrace dump start ------"); |
807 |
> |
for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { |
808 |
> |
String name = info.getThreadName(); |
809 |
> |
if ("Signal Dispatcher".equals(name)) |
810 |
> |
continue; |
811 |
> |
if ("Reference Handler".equals(name) |
812 |
> |
&& info.getLockName().startsWith("java.lang.ref.Reference$Lock")) |
813 |
> |
continue; |
814 |
> |
if ("Finalizer".equals(name) |
815 |
> |
&& info.getLockName().startsWith("java.lang.ref.ReferenceQueue$Lock")) |
816 |
> |
continue; |
817 |
|
System.err.print(info); |
818 |
+ |
} |
819 |
+ |
System.err.println("------ stacktrace dump end ------"); |
820 |
|
} |
821 |
|
|
822 |
|
/** |