6222101924
Motivation: We can use lambdas now as we use Java8. Modification: use lambda function for all package, #8751 only migrate transport package. Result: Code cleanup.
220 lines
8.6 KiB
Java
220 lines
8.6 KiB
Java
/*
|
|
* Copyright 2016 The Netty Project
|
|
*
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
package io.netty.util.concurrent;
|
|
|
|
import org.junit.Test;
|
|
|
|
import java.security.Permission;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNull;
|
|
|
|
public class DefaultThreadFactoryTest {
|
|
@Test(timeout = 2000)
|
|
public void testDescendantThreadGroups() throws InterruptedException {
|
|
final SecurityManager current = System.getSecurityManager();
|
|
|
|
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) {
|
|
}
|
|
});
|
|
|
|
// holder for the thread factory, plays the role of a global singleton
|
|
final AtomicReference<DefaultThreadFactory> factory = new AtomicReference<>();
|
|
final AtomicInteger counter = new AtomicInteger();
|
|
final Runnable task = counter::incrementAndGet;
|
|
|
|
final AtomicReference<Throwable> interrupted = new AtomicReference<>();
|
|
|
|
// 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"), () -> {
|
|
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"), () -> {
|
|
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 {
|
|
System.setSecurityManager(current);
|
|
}
|
|
}
|
|
|
|
// test that when DefaultThreadFactory is constructed with a sticky thread group, threads
|
|
// created by it have the sticky thread group
|
|
@Test(timeout = 2000)
|
|
public void testDefaultThreadFactoryStickyThreadGroupConstructor() throws InterruptedException {
|
|
final ThreadGroup sticky = new ThreadGroup("sticky");
|
|
runStickyThreadGroupTest(
|
|
() -> new DefaultThreadFactory("test", false, Thread.NORM_PRIORITY, sticky),
|
|
sticky);
|
|
}
|
|
|
|
// test that when DefaultThreadFactory is constructed it is sticky to the thread group from the thread group of the
|
|
// thread that created it
|
|
@Test(timeout = 2000)
|
|
public void testDefaultThreadFactoryInheritsThreadGroup() throws InterruptedException {
|
|
final ThreadGroup sticky = new ThreadGroup("sticky");
|
|
|
|
runStickyThreadGroupTest(
|
|
() -> {
|
|
final AtomicReference<DefaultThreadFactory> factory =
|
|
new AtomicReference<>();
|
|
final Thread thread = new Thread(sticky, () -> factory.set(new DefaultThreadFactory("test")));
|
|
thread.start();
|
|
thread.join();
|
|
return factory.get();
|
|
},
|
|
sticky);
|
|
}
|
|
|
|
// test that when a security manager is installed that provides a ThreadGroup, DefaultThreadFactory inherits from
|
|
// the security manager
|
|
@Test(timeout = 2000)
|
|
public void testDefaultThreadFactoryInheritsThreadGroupFromSecurityManager() throws InterruptedException {
|
|
final SecurityManager current = System.getSecurityManager();
|
|
|
|
try {
|
|
final ThreadGroup sticky = new ThreadGroup("sticky");
|
|
System.setSecurityManager(new SecurityManager() {
|
|
@Override
|
|
public ThreadGroup getThreadGroup() {
|
|
return sticky;
|
|
}
|
|
|
|
// so we can restore the security manager at the end of the test
|
|
@Override
|
|
public void checkPermission(Permission perm) {
|
|
}
|
|
});
|
|
runStickyThreadGroupTest(
|
|
() -> new DefaultThreadFactory("test"),
|
|
sticky);
|
|
} finally {
|
|
System.setSecurityManager(current);
|
|
}
|
|
}
|
|
|
|
private static void runStickyThreadGroupTest(
|
|
final Callable<DefaultThreadFactory> callable,
|
|
final ThreadGroup expected) throws InterruptedException {
|
|
final AtomicReference<ThreadGroup> captured = new AtomicReference<>();
|
|
final AtomicReference<Throwable> exception = new AtomicReference<>();
|
|
|
|
final Thread first = new Thread(new ThreadGroup("wrong"), () -> {
|
|
final DefaultThreadFactory factory;
|
|
try {
|
|
factory = callable.call();
|
|
} catch (Exception e) {
|
|
exception.set(e);
|
|
throw new RuntimeException(e);
|
|
}
|
|
final Thread t = factory.newThread(() -> {
|
|
});
|
|
captured.set(t.getThreadGroup());
|
|
});
|
|
first.start();
|
|
first.join();
|
|
|
|
assertNull(exception.get());
|
|
|
|
assertEquals(expected, captured.get());
|
|
}
|
|
|
|
// test that when DefaultThreadFactory is constructed without a sticky thread group, threads
|
|
// created by it inherit the correct thread group
|
|
@Test(timeout = 2000)
|
|
public void testDefaultThreadFactoryNonStickyThreadGroupConstructor() throws InterruptedException {
|
|
|
|
final AtomicReference<DefaultThreadFactory> factory = new AtomicReference<>();
|
|
final AtomicReference<ThreadGroup> firstCaptured = new AtomicReference<>();
|
|
|
|
final ThreadGroup firstGroup = new ThreadGroup("first");
|
|
final Thread first = new Thread(firstGroup, () -> {
|
|
factory.set(new DefaultThreadFactory("sticky", false, Thread.NORM_PRIORITY, null));
|
|
final Thread t = factory.get().newThread(() -> {
|
|
});
|
|
firstCaptured.set(t.getThreadGroup());
|
|
});
|
|
first.start();
|
|
first.join();
|
|
|
|
assertEquals(firstGroup, firstCaptured.get());
|
|
|
|
final AtomicReference<ThreadGroup> secondCaptured = new AtomicReference<>();
|
|
|
|
final ThreadGroup secondGroup = new ThreadGroup("second");
|
|
final Thread second = new Thread(secondGroup, () -> {
|
|
final Thread t = factory.get().newThread(() -> {
|
|
});
|
|
secondCaptured.set(t.getThreadGroup());
|
|
});
|
|
second.start();
|
|
second.join();
|
|
|
|
assertEquals(secondGroup, secondCaptured.get());
|
|
}
|
|
}
|