While there are use cases where lightweight threads are a benefit, I think a web crawler is pretty much the ideal case for async/await, given you are almost exclusively waiting. Although I must admit I don't really understand this example, why is the fetching being parallellized, like you typically want to add sleeps, even with a single thread you've got yourself a gatling gun that can DoS a website if you aren't careful.
There's also some optimizations that could be made. Instead of having
synchronized (seen) {
if (!seen.contains(u)) {
seen.add(u);
// ...
}
}
you can get rid of the synchronization with
// seen = ConcurrentHashMap.newKeySet()
if (seen.add(u)) {
// ...
}