根据您的字典的外观,如果您可以让每个线程构建独立的子树,您可能根本不需要锁。如果这不是在线算法,请按前缀对单词进行预排序(如果您有 < 26 个线程,则为第一个字母,如果您有更多或您知道数据不平衡,则为第一个和第二个,例如,90% 的词从 A) 开始。基本上,这将是一个 O(n) 操作,您执行一次计算以计算有多少以给定字母开头的单词,然后执行一次排序(按照您选择的前缀进行基数排序)。然后,划分线程之间的前缀,让每个线程构建这些独立的子树。最后,让一个线程将这些子树中的每一个添加到根。我将在下面介绍一个示例。
您的词典:
Bark
Apple
Cookie
和
Baby
Corn
Blue
Cake
Bacon
排序后:
苹果
和
树皮
婴儿
蓝
培根
玉米
饼干
蛋糕
然后我们在线程之间划分前缀。对于此示例,我们有 3 个线程,它们获取前缀 [A][B][C],并构建以下树:
一个--| 乙--------| C --------|
PN |-- A ---| 洛---| 一种
PDRBCUORK
乐视网
埃尼
乙
然后你有一个线程在根处将这些组合起来,例如:
|----------- 根目录------|
一个--| 乙--------| C --------|
PN |-- A ---| 洛---| 一种
PDRBCUORK
乐视网
埃尼
乙
我希望这是有道理的。
这种方法的优点:线程基本上独立工作,您不必处理获取和释放锁的开销。
这种方法的缺点:如果您对字典一无所知,可能会出现严重的工作负载不平衡,并且在最坏的情况下(例如,所有单词都以“A”开头)它会恢复为基本上是单线程构建一颗树。有几种方法可以使这更好,例如,您可以在排序时添加一些检查,这样如果在处理单个字母前缀时工作量严重不平衡,则可以使用前 2 个字母,但实际上您可以t保证它将是平衡的。
如果假设您有 20 个线程并按第一个字母排序,那么您有时也可能有空闲线程,那么您将有大约 6 个线程必须执行两个子树,而其中 14 个线程在一半时间内处于空闲状态。您也许可以进一步细分子树来处理这个问题,但这是在预处理步骤上花费的额外时间。
Anyway, no guarantees that this is faster than your method, but its something to consider.