I have written the program for thread factoring. Tests are working for every method, except result. As I understand, I'm including threads that threw and exception, but not including finished threads. Here's the description hint I got:
Thread newThread (Runnable runnable) - Creates and registers a new Thread. Name of the thread should be "-worker-n", where n is a number of a thread. A ThreadUnion must monitor execution of a created thread - refer to results() method.
List results() - Returns a list of results of finished threads. No results must be returned for threads that are not finished yet. A result must contain a thread name, a timestamp when it finished execution and a Throwable if it was thrown
I got another hint, that I should use catch-finally and Runnable r that was passed as parameter to newThread, but not sure how to implement it.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadUnionImpl implements ThreadUnion{
private final String name;
private final AtomicInteger threadCount = new AtomicInteger(0);
private final List<FinishedThreadResult> threadList = Collections.synchronizedList(new ArrayList<>());
private boolean shutdownRequested = false;
public ThreadUnionImpl(String name) {
this.name = name;
}
@Override
public int totalSize() {
return threadCount.get();
}
@Override
public int activeSize() {
return (int)Thread.getAllStackTraces().keySet().stream()
.filter(thread -> thread.getName().startsWith(name + "-worker-"))
.count();
}
@Override
public void shutdown() {
shutdownRequested = true;
Thread.getAllStackTraces().keySet().stream()
.filter(thread -> thread.getName().startsWith(name + "-worker-"))
.forEach(Thread::interrupt);
Thread.getAllStackTraces().keySet().stream()
.filter(thread -> thread.getName().startsWith(name + "-worker-"))
.forEach(Thread::interrupt);
}
@Override
public boolean isShutdown() {
return shutdownRequested;
}
@Override
public void awaitTermination() {
Thread.getAllStackTraces().keySet().stream()
.filter(thread -> thread.getName().startsWith(name + "-worker-"))
.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
@Override
public boolean isFinished() {
return shutdownRequested && activeSize() == 0;
}
@Override
public List<FinishedThreadResult> results() {
return threadList;
}
@Override
public Thread newThread(Runnable r) {
if (shutdownRequested) throw new IllegalStateException();
String threadName = this.name + "-worker-" + threadCount.getAndIncrement();
Thread thread = new Thread(r, threadName);
thread.setUncaughtExceptionHandler((t, e) -> {
threadList.add(new FinishedThreadResult(t.getName(), e));
});
return thread;
}
}
One test is failing, providing response:
org.opentest4j.AssertionFailedError:
Expected :7Actual :4
To ensure that you include finished threads in your results() method while excluding threads that are still active, you need to update your implementation. The key is to track the threads that have finished executing and retrieve their results when results() method is called.
You can achieve this by updating the newThread() method to wrap the provided Runnable with a custom Runnable implementation that catches exceptions and stores the result upon completion.