Java-通过返回新值实现线程安全集方法

发布于 2025-01-26 07:38:29 字数 2987 浏览 1 评论 0原文

我正在尝试为AtomicInteger实施设定方法并返回新值。不幸的是,这涉及比赛条件。我认为这是因为两个语句this.counter.set(newValue);返回this.counter.get();如果我让它们一起运行,则不是原子。我还尝试使用同步块,但也无济于事。您知道如何设置一个新值并以原子方法返回值?由于原因,我不能更改方法签名。

这是设定方法应该是:

import java.util.concurrent.atomic.AtomicInteger;

import util.Incrementer;

public class AtomicIncrementer implements Incrementer {

    private AtomicInteger counter = new AtomicInteger();
    private int startValue;

    public AtomicIncrementer(int startValue) {
        this.startValue = startValue;
        this.counter.set(startValue);
    }

    @Override
    public int setValue(int newValue) {
        // TODO: implement, do not change method the signature!
        synchronized (this.counter) {
            this.counter.set(newValue);
            return this.counter.get();
        }

    }


}

我正在进行此测试的课程:

package incrementer;

import impl.AtomicIncrementer;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TestAtomicIncrementer {

    private final int defaultThreadPoolSize = 8;
    private final int defaultThreadCount = 24;

    @Test
    void testSetValue() {
        int newValue = (int) (Math.random() * 100);
        AtomicIncrementer inc = new AtomicIncrementer(0);
        ExecutorService executor = Executors.newFixedThreadPool(defaultThreadPoolSize);
        for(int i = 0; i < defaultThreadCount; i++) {
            executor.submit(() -> {
                for(int j = 0; j < 1000; j++) {
                    inc.increment();
                }
                return null;
            });
        }
        try {
            assertEquals(newValue, executor.submit(() -> inc.setValue(newValue)).get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        try {
            executor.shutdown();
            assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        inc.setValue(newValue);
        assertEquals(newValue, inc.getValue());
    }

    private List<Future<Integer>> executeOperation(Callable<Integer> op, AtomicIncrementer inc, int threadCount, int threadPoolSize) {
        ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
        List<Callable<Integer>> ops = new ArrayList<>(threadCount);
        for(int i = 0; i < threadCount; i++) {
            ops.add(op);
        }
        try {
            return executor.invokeAll(ops);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

有时是测试成功,有时不是,这对我来说似乎是一个种族条件问题。

你怎么认为?

I am trying to implement a set method for an AtomicInteger and return the new value. Unfortunately, it comes to race conditions. I think it is because the two statements this.counter.set(newValue); and return this.counter.get(); are not Atomic if I let them run together. I also tried to use a synchronized block, but it did not help either. Do you know how I can set a new Value and return the value in an atomic method? For reasons, I can't change the method signature.

Here is the Class where the set method should be:

import java.util.concurrent.atomic.AtomicInteger;

import util.Incrementer;

public class AtomicIncrementer implements Incrementer {

    private AtomicInteger counter = new AtomicInteger();
    private int startValue;

    public AtomicIncrementer(int startValue) {
        this.startValue = startValue;
        this.counter.set(startValue);
    }

    @Override
    public int setValue(int newValue) {
        // TODO: implement, do not change method the signature!
        synchronized (this.counter) {
            this.counter.set(newValue);
            return this.counter.get();
        }

    }


}

I am running this test:

package incrementer;

import impl.AtomicIncrementer;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TestAtomicIncrementer {

    private final int defaultThreadPoolSize = 8;
    private final int defaultThreadCount = 24;

    @Test
    void testSetValue() {
        int newValue = (int) (Math.random() * 100);
        AtomicIncrementer inc = new AtomicIncrementer(0);
        ExecutorService executor = Executors.newFixedThreadPool(defaultThreadPoolSize);
        for(int i = 0; i < defaultThreadCount; i++) {
            executor.submit(() -> {
                for(int j = 0; j < 1000; j++) {
                    inc.increment();
                }
                return null;
            });
        }
        try {
            assertEquals(newValue, executor.submit(() -> inc.setValue(newValue)).get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        try {
            executor.shutdown();
            assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        inc.setValue(newValue);
        assertEquals(newValue, inc.getValue());
    }

    private List<Future<Integer>> executeOperation(Callable<Integer> op, AtomicIncrementer inc, int threadCount, int threadPoolSize) {
        ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
        List<Callable<Integer>> ops = new ArrayList<>(threadCount);
        for(int i = 0; i < threadCount; i++) {
            ops.add(op);
        }
        try {
            return executor.invokeAll(ops);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

Sometimes the test success and sometimes not, which seems like a race condition Problem for me.

What do you think?

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文