为了检查主题我写了代码:
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
if (test() != 5 * 100) {
throw new RuntimeException("main");
}
}
test();
}
private static long test() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(100);
CountDownLatch countDownLatch = new CountDownLatch(100 * 5);
Set<Thread> threads = Collections.synchronizedSet(new HashSet<>());
AtomicLong atomicLong = new AtomicLong();
for (int i = 0; i < 5 * 100; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
threads.add(Thread.currentThread());
atomicLong.incrementAndGet();
countDownLatch.countDown();
} catch (Exception e) {
System.out.println(e);
}
}
});
}
executorService.shutdown();
countDownLatch.await();
if (threads.size() != 100) {
throw new RuntimeException("test");
}
return atomicLong.get();
}
}
如您所见,我使用HashSet<Thread>
仅当Thread不可变时,它的用法才是正确的。至少在考试中。
据我所知,equals / hashCode未被覆盖,因此继承自Object。
因此,如果我的测试不正确以及错误在哪里,请回答 如果你知道更聪明的方式,请分享一下。
答案 0 :(得分:2)
正如我的评论中所提到的,我认为你的代码实际上设法验证test()
创建100个线程并使用它们执行500个小任务。如果情况并非如此,你的RuntimeException
断言肯定会被解雇。
另一种验证方法是使用ThreadLocal
来计算实际运行的线程数。
我创建了以下单元测试,它使用ThreadLocal
来计算Executor
创建的线程数。尝试研究它的输出以确信创建的线程数。
@Test
public void threadCounter() throws Throwable {
ThreadLocal<Integer> number = new ThreadLocal<Integer>() {
private final AtomicInteger values = new AtomicInteger();
@Override
protected Integer initialValue() {
return values.getAndIncrement();
}
};
ExecutorService threadPool = Executors.newFixedThreadPool(100);
for (int i = 0 ; i < 500 ; i++) {
final int count = i;
threadPool.submit(() -> System.out.printf("%-4s : %-20s - %s\n", count, Thread.currentThread().getName(), number.get()));
}
threadPool.shutdown();
threadPool.awaitTermination(10, TimeUnit.SECONDS);
Assert.assertEquals(100, number.get().intValue());
}
答案 1 :(得分:1)
我不确定我是否正确解决了线程[池]'重用'线程的问题。
池线程(a.k.a。,工作线程)具有run()
方法,就像任何其他线程一样,这就是“重用”的地方。基本上,工作线程的run()
方法从队列中选择任务(即客户端提供的Runnable
对象)并运行它们:
class ReallySimplePoolWorker {
public ReallySimplePoolWorker(BlockingQueue<Runnable> workQueue) {
this->workQueue = workQueue;
}
public void Run( ) {
while (...not shutting down...) {
Runnable task = workQueue.take();
try {
task.run();
} catch (Exception ex) {
...notify the pool object of the exception...
}
}
}
private final BlockingQueue<Runnable> workQueue;
}