无锁编程的主要困难在于架构层面。您需要以一种不会干扰彼此数据的方式设计代码和算法。您需要在可以单独运行且尤其是独立运行的单个任务中“阻止”您的代码。但是,一旦您深入研究了这些想法,您就会开始想知道为什么以前使用了如此多的阻塞。
示例:给定的是一个句子数组,你想计算每个句子中的单词,并且你想以一种线程化的方式来做。
首先,您需要查明“阻塞点”,即线程可能发生冲突的地方。在这种情况下,数据源(数组)和数据输出是结果的计数和最终 println。因此,您需要找到一种方法来做到这一点,而无需同步或锁定这些数据源。幸运的是 Java 提供了 Atomics 类,它允许并发访问而不阻塞,并且允许大量智能编码。
对于 Array 访问,有两个选项:您可以使用 AtomicInteger 作为索引,并让线程getAndIncremnt()
在其上获取它们的工作索引。如果您确实知道您有多少线程或您的数据值有多长,这将很有用(提示:并非如此)。
第二个选项是您从一开始就为每个线程分配一个确定性索引,以确保没有线程干扰其他线程。如果您的 iE 有 4 个线程和 256 个数据值,您可以以 4 的增量分配索引值。所以线程 A 得到 0、4、8,......线程 B 得到 1、5、9,......等等上。这确保了任何线程都不会与设计上的任何其他线程发生冲突。
最后的计数同样容易:首先让线程在内部计算单词,然后使用 将总和添加到全局 AtomicInteger 中addAndGet()
。
现在您只需要弄清楚何时打印该值。答案是“当最后一个线程完成时”。这可以再次使用 AtomicInteger 作为计数器并让每个线程decrementAndGet()
检查它们是否得到 0,这意味着它们是最后一个线程并且需要打印结果。然后你可以使用一个 Barrier 类,它会阻塞,但在某个不再重要的地方,因为无论如何所有工作都在此时完成。