-3

我知道编写非阻塞(无锁)程序真的很困难。在使用基本构建块(即 CAS 操作)在 Java 中编写程序时,您仍然必须注意所有事情。

- 编辑 -

如果我有共享资源并且我不想锁定共享资源,则可能希望在 while 循环中使用 compareAndSet(expectedValue, valueToSet) 指令,直到我成功。在 java 中,我们有支持此操作的 AtomicXXX 类。比如写一个非阻塞栈Refer(Java Concurrency in Practice)

我需要记住的所有事情,所有测试场景都可以在那里..

4

1 回答 1

3

无锁编程的主要困难在于架构层面。您需要以一种不会干扰彼此数据的方式设计代码和算法。您需要在可以单独运行且尤其是独立运行的单个任务中“阻止”您的代码。但是,一旦您深入研究了这些想法,您就会开始想知道为什么以前使用了如此多的阻塞。

示例:给定的是一个句子数组,你想计算每个句子中的单词,并且你想以一种线程化的方式来做。

首先,您需要查明“阻塞点”,即线程可能发生冲突的地方。在这种情况下,数据源(数组)和数据输出是结果的计数和最终 println。因此,您需要找到一种方法来做到这一点,而无需同步或锁定这些数据源。幸运的是 Java 提供了 Atomics 类,它允许并发访问而不阻塞,并且允许大量智能编码。

对于 Array 访问,有两个选项:您可以使用 AtomicInteger 作为索引,并让线程getAndIncremnt()在其上获取它们的工作索引。如果您确实知道您有多少线程或您的数据值有多长,这将很有用(提示:并非如此)。

第二个选项是您从一开始就为每个线程分配一个确定性索引,以确保没有线程干扰其他线程。如果您的 iE 有 4 个线程和 256 个数据值,您可以以 4 的增量分配索引值。所以线程 A 得到 0、4、8,......线程 B 得到 1、5、9,......等等上。这确保了任何线程都不会与设计上的任何其他线程发生冲突。

最后的计数同样容易:首先让线程在内部计算单词,然后使用 将总和添加到全局 AtomicInteger 中addAndGet()

现在您只需要弄清楚何时打印该值。答案是“当最后一个线程完成时”。这可以再次使用 AtomicInteger 作为计数器并让每个线程decrementAndGet()检查它们是否得到 0,这意味着它们是最后一个线程并且需要打印结果。然后你可以使用一个 Barrier 类,它会阻塞,但在某个不再重要的地方,因为无论如何所有工作都在此时完成。

于 2013-11-03T10:36:21.690 回答