@Override
    public Thread newThread(Runnable r) {
        Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
        try {
            if (t.isDaemon() != daemon) {
                t.setDaemon(daemon);
            }

            if (t.getPriority() != priority) {
                t.setPriority(priority);
            }
        } catch (Exception ignored) {
            // Doesn't matter even if failed to set.
        }
        return t;
    }
@Test
    @Timeout(value = 2000, unit = TimeUnit.MILLISECONDS)
    public void testDescendantThreadGroups() throws InterruptedException {
        final SecurityManager current = System.getSecurityManager();

        boolean securityManagerSet = false;
        try {
            try {
                // install security manager that only allows parent thread groups to mess with descendant thread groups
                System.setSecurityManager(new SecurityManager() {
                    @Override
                    public void checkAccess(ThreadGroup g) {
                        final ThreadGroup source = Thread.currentThread().getThreadGroup();

                        if (source != null) {
                            if (!source.parentOf(g)) {
                                throw new SecurityException("source group is not an ancestor of the target group");
                            }
                            super.checkAccess(g);
                        }
                    }

                    // so we can restore the security manager at the end of the test
                    @Override
                    public void checkPermission(Permission perm) {
                    }
                });
            } catch (UnsupportedOperationException e) {
                Assumptions.assumeFalse(true, "Setting SecurityManager not supported");
            }
            securityManagerSet = true;

            // holder for the thread factory, plays the role of a global singleton
            final AtomicReference<DefaultThreadFactory> factory = new AtomicReference<DefaultThreadFactory>();
            final AtomicInteger counter = new AtomicInteger();
            final Runnable task = new Runnable() {
                @Override
                public void run() {
                    counter.incrementAndGet();
                }
            };

            final AtomicReference<Throwable> interrupted = new AtomicReference<Throwable>();

            // create the thread factory, since we are running the thread group brother, the thread
            // factory will now forever be tied to that group
            // we then create a thread from the factory to run a "task" for us
            final Thread first = new Thread(new ThreadGroup("brother"), new Runnable() {
                @Override
                public void run() {
                    factory.set(new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, null));
                    final Thread t = factory.get().newThread(task);
                    t.start();
                    try {
                        t.join();
                    } catch (InterruptedException e) {
                        interrupted.set(e);
                        Thread.currentThread().interrupt();
                    }
                }
            });
            first.start();
            first.join();

            assertNull(interrupted.get());

            // now we will use factory again, this time from a sibling thread group sister
            // if DefaultThreadFactory is "sticky" about thread groups, a security manager
            // that forbids sibling thread groups from messing with each other will strike this down
            final Thread second = new Thread(new ThreadGroup("sister"), new Runnable() {
                @Override
                public void run() {
                    final Thread t = factory.get().newThread(task);
                    t.start();
                    try {
                        t.join();
                    } catch (InterruptedException e) {
                        interrupted.set(e);
                        Thread.currentThread().interrupt();
                    }
                }
            });
            second.start();
            second.join();

            assertNull(interrupted.get());

            assertEquals(2, counter.get());
        } finally {
            if (securityManagerSet) {
                System.setSecurityManager(current);
            }
        }
    }