Java同步问题

发布于 2024-11-16 08:54:09 字数 1835 浏览 3 评论 0原文

我刚刚开始学习 Java 并发性,并且从以下代码中得到一些奇怪的输出:

ThreadSafe.java:

public class ThreadSafe {
    private int value;

    public ThreadSafe() {
        value = 0;
    }

    public synchronized int getNext() {
        if (value >= 10000) {
            value = 0;
        }
        return value++;
    }
}

RunnableImpl.java:

public class RunnableImpl implements Runnable {
    private String name;
    private ThreadSafe ts;

    public RunnableImpl(String name, ThreadSafe ts) {
        this.name = name;
        this.ts = ts;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(name + ": " + ts.getNext());
        }
    }
}

Main.java:

public class Main {
    public static void main(String[] args) {
        ThreadSafe ts = new ThreadSafe();

        Runnable a = new RunnableImpl("A", ts);
        Runnable b = new RunnableImpl("B", ts);

        new Thread(a).start();
        new Thread(b).start();
    }
}

每当线程关闭时,我都会得到如下输出:

B: 7320
B: 7321
A: 4278 // What?
A: 7323
A: 7324

Going back up the AB 关闭的输出:

A: 4275
A: 4276
A: 4277
B: 2279 // ROBBLE ROBBLE!
B: 4279
B: 4280

我可以看到 A 早些时候在 4277 处停止,并在跳过 7322 之前在 4278 处恢复,继续 7323。 value++++value 都会发生这种情况。我的理解是,synchronized 会让每个线程的 getNext() 方法调用完成,然后再让任何其他线程执行该方法。

当我在 threadsafe.java 中使用 private volatile int value; 时,我得到类似于以下内容的输出:

A: 8511
A: 8512
A: 8513
B: 7022 // Meh.
B: 8514
B: 8515

这次没有跳过任何数字(来自 ++value code>,仍然跳过 value++),但输出似乎仍然在第一次使用缓存值。

我在这里忽略了什么?

I am just starting to learn about Java concurrency and I am getting some strange output from the following code:

ThreadSafe.java:

public class ThreadSafe {
    private int value;

    public ThreadSafe() {
        value = 0;
    }

    public synchronized int getNext() {
        if (value >= 10000) {
            value = 0;
        }
        return value++;
    }
}

RunnableImpl.java:

public class RunnableImpl implements Runnable {
    private String name;
    private ThreadSafe ts;

    public RunnableImpl(String name, ThreadSafe ts) {
        this.name = name;
        this.ts = ts;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(name + ": " + ts.getNext());
        }
    }
}

Main.java:

public class Main {
    public static void main(String[] args) {
        ThreadSafe ts = new ThreadSafe();

        Runnable a = new RunnableImpl("A", ts);
        Runnable b = new RunnableImpl("B", ts);

        new Thread(a).start();
        new Thread(b).start();
    }
}

Whenever the threads switch off, I get output like the following:

B: 7320
B: 7321
A: 4278 // What?
A: 7323
A: 7324

Going back up the output where A and B switch off:

A: 4275
A: 4276
A: 4277
B: 2279 // ROBBLE ROBBLE!
B: 4279
B: 4280

I can see that A left off at 4277 earlier on and picked up at 4278 before skipping 7322 and continuing on with 7323. This happens with both value++ and ++value. My understanding was that synchronized would let each thread's method invocation of getNext() complete before letting any other threads execute that method.

When I use private volatile int value; in threadsafe.java I get output similar to the following:

A: 8511
A: 8512
A: 8513
B: 7022 // Meh.
B: 8514
B: 8515

This time no numbers were skipped (from ++value, still skips with value++) but the output still seems to be using a cached value for the first go.

What am I overlooking here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

单调的奢华 2024-11-23 08:54:09

您的 ThreadSafe 类没问题。发生这种情况很可能是因为线程调度。也就是说,在第一个示例中,线程“A”在从实例获取 4278 之后但在将其打印到终端之前被取消调度。

然后“B”运行了一段时间,获取了 7322 以内的所有值,并在取消调度之前打印了 7321 以内的所有值,此时“A”再次被调度,下一步是打印它拥有的值先前获取的值 (4278),并继续使用 ThreadSafe 类中的下一个值 (7323)。

所以你的问题是,虽然获取数字是正确的线程安全的,但打印它们却不是。

Your ThreadSafe class is fine. This is happening most probably because of the thread scheduling. Namely, in the first example, thread "A" got de-scheduled after fetching 4278 from the instance, but before printing it to the terminal.

Then "B" ran for a while, fetching all values up to 7322, and printing all values up to 7321 before being de-scheduled, at which point "A" was scheduled again, and its next step was to print the value it had previously fetched (4278), and the continuing with the next value from the ThreadSafe class (7323).

So your problem is that while fetching the numbers is properly thread-safe, printing them is not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文