There is no need to have BoggleList:CurateList function. The word should be just ignored and there should be no need to create a new file. The idea was to store a curated list for subsequent runs to reduce load times. To do this, actually the full tree of dictionary should be persisted and deserialzed in case it matches the rules for which we need to construct the tree.

Maintaining 'Q' and 'U' together is deeply embedded in the whole program. This takes away some flexibility that comes with defining your own ruleset. Hence the idea should be to remove the constraint while adding it to the tree while loading the list. This would make it even more efficient because instead of String, we would be able to use 'readonly char' type that is much lighter for all operations and memory usage.

Curated list will corrupt the data if boardlength is different but the min word length is passed the same. This is because max word size, or boardlength^2 + 1.

For each thread, store the words in local copy to the threaf and at the end of all the threads, collect them in one list. This way you would be able to remove all the locks.