java - 我的多线程 "fizz buzz"实现线程安全吗?

标签 java multithreading

出于教育目的,我正在使用多线程实现经典的“嘶嘶声”问题。

“嘶嘶声”游戏是:

The player designated to go first says the number "1", and each player thenceforth counts one number in turn. However, any number divisible by three is replaced by the word fizz and any divisible by five by the word buzz. Numbers divisible by both become fizz buzz

在我的实现中,我有 4 个线程:

  • 如果第一个线程不是 3 或 5 的倍数,则打印数字并递增当前计数器。
  • 第二个线程打印“fizz”...
  • 第三个线程打印“嗡嗡声”……
  • 第四个线程打印“fizz buzz”...

我不使用任何锁定和线程同步机制。 我的多线程“fizz buzz”实现线程安全吗?如果不是,为什么? 我在实现代码中为“可疑”的地方添加了注释。

我的实现:

package threads;    
import java.util.function.IntFunction;    
public class FizzBuzzGameRunner {

    // not volatile
    // if other thread updates currentNum and current thread will see old (cached) value
    // nothing bad can happen, just burn some CPU cycles uselessly
    private int currentNum = 1;

    public static void main(String... args) throws InterruptedException {
        FizzBuzzGameRunner fizzBuzzGame = new FizzBuzzGameRunner();
        startAll(
                fizzBuzzGame.createRunnable(n -> (n % 3 != 0 && n % 5 != 0) ? String.valueOf(n) : null),
                fizzBuzzGame.createRunnable(n -> (n % 3 == 0 && n % 5 != 0) ? "fizz" : null),
                fizzBuzzGame.createRunnable(n -> (n % 3 != 0 && n % 5 == 0) ? "buzz" : null),
                fizzBuzzGame.createRunnable(n -> (n % 3 == 0 && n % 5 == 0) ? "fizz buzz" : null)
        );
        Thread.sleep(1000);
    }

    private static void startAll(Runnable... workers) {
        for (Runnable w : workers) {
            Thread t = new Thread(w);
            t.setDaemon(true);
            t.start();
        }
    }

    private Runnable createRunnable(IntFunction<String> singleStep) {
        return () -> {
            while (true) {
                int currNum = this.currentNum;
                // no synchronization
                String result = singleStep.apply(currNum);
                if (result != null) {
                    //Even without synchronization this block will be
                    //executed maximum by single thread simultaneously.
                    //Because each thread increments this.currentNum as part of that action,
                    //but no other thread will increment for the same value.
                    System.out.println(result);
                    this.currentNum++;
                }
            }
        };
    }
}

我明白我的例子完全是人为的。实现多线程“Fizz Buzz”算法启发了一本着名的书来准备“coding interview”。我只是想证明书中的示例(需要有 4 个线程)可以在不使用同步和锁的情况下解决。

最佳答案

它不是无竞争的(这就是我认为你真正要问的),因为线程在 currentNum 被另一个线程写入时读取它,没有任何同步。不保证每个线程都能看到最新的值 - 每个线程都会看到它自己上次写入的值,或者任何其他线程自此之后写入的任何值。

这可能意味着您最终在任何线程中都没有向前推进,因为每个线程可能根本看不到任何其他线程中所做的更改。您可以使用 AtomicInteger 来解决该问题。

我也不确定 this.currentNum++; 的效果是否保证可以按照它们在源线程中的顺序被其他线程看到。我怀疑理论上,输出和增量可以重新排序,例如:

              this.currentNum++;
              System.out.println(result);

这可能会导致输出不一致。

关于java - 我的多线程 "fizz buzz"实现线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53103065/

相关文章:

java - 为基于 Java 的 Web 应用程序生成 GUI

java - @远程JNDI通信: Wildfly to JBoss AS 5. 1.0.GA

java - Eclipse Dynamic Web Project如何组织文件?

multithreading - 哪种线程实践在 90% 的时间里都是好的?

java - 如何在Java中在服务器端执行线程安全方法?

multithreading - 多线程对 IO-bound 操作有意义吗?

java - Spring 启动: Bypass OncePerRequestFilter filters

java - Heapify功能不起作用

c++ - decaf 线程 vs boost 线程 vs omnithreads

python - 在线程中运行 Python 脚本并在 GUI 中将 stdout/stderr 重定向到 wx.TextCtrl