Java 从其他线程更新AtomicInteger

Java 从其他线程更新AtomicInteger,java,multithreading,atomicinteger,Java,Multithreading,Atomicinteger,我有一个类,它在各自的线程上创建了许多新对象,我希望保持线程间的运行计数。我想要一个AtomicInteger,但它没有达到我的预期,而是得到了一个更小的版本。我假设这是一个竞赛条件错误,但我不能完全确定 A创建了这个测试示例,它重新创建了我想要做的事情 public class Test { public static void main(String args[]) { AtomicInteger total = new AtomicInteger(0);

我有一个类,它在各自的线程上创建了许多新对象,我希望保持线程间的运行计数。我想要一个
AtomicInteger
,但它没有达到我的预期,而是得到了一个更小的版本。我假设这是一个竞赛条件错误,但我不能完全确定

A创建了这个测试示例,它重新创建了我想要做的事情

public class Test {

    public static void main(String args[]) {
        AtomicInteger total = new AtomicInteger(0);
        for (int i = 0; i < 10; i++) {

            DoThing doThing = new DoThing();

            Thread thread = new Thread(doThing);
            thread.start();
            total.addAndGet(doThing.getTally());
        }

        System.out.println(total.get());
    }
}

class DoThing implements Runnable {

    int tally = 0;
    @Override
    public void run() {

        for(int i = 0; i< 100; i++) {
            tally++;
        }

        System.out.println("Tally is " + tally);

    }

    public int getTally() {
        return tally;
    }
}
当我希望最终输出为1000时。如何跨线程递增


提前感谢。

是的,有一场数据竞赛。争用是在调用
doThing.gettaly()
的主线程和启动的“worker”线程之间进行的。看起来每次主线程都能够可靠地从每个工作线程获得“计数”,而工作线程甚至还没有机会进入其
for
循环。甚至在worker调用其
run()
方法之前就可能发生这种情况

您的主线程需要加入工作线程:

  • 创建并启动十个工作线程,并将每个工作线程添加到
    列表中
  • 然后在一个单独的循环中,为列表中的每个线程调用
    t.join()
    t.join()
    函数等待线程
    t
    完成其工作
  • 最后,把这些数字加起来
在示例代码中,total仅从主线程访问。将其原子化不会对结果产生任何影响。您应该将原子值传递给线程并增加其中的值。或者使用长加法器(增量法)。
在主线程中打印原子值之前,必须等待所有线程完成。
如果您想使用低级阻塞,可以使用CyclicBarrier使主线程等待所有线程

CountDownLatch闩锁=新的CountDownLatch(10);
CountDownLatch latch = new CountDownLatch(10);
List<DoThing> things = new ArrayList();
AtomicInteger total = new AtomicInteger(0);
    for (int i = 0; i < 10; i++) {

        DoThing doThing = new DoThing(latch);
        things.add(doThing);
        Thread thread = new Thread(doThing);
        thread.start();
        total.addAndGet(doThing.getTally());
    }
// Wait till all the threads are done.
// Each thread counts the latch down
latch.await()
int total = 0;

// Calculate sum after all the threads are done.
for (DoThing thing: things) {
    total += thing.getTally();
}
System.out.println(total);



class DoThing implements Runnable {

    private CountDownLatch latch;

    public DoThing(CountDownLatch latch) {
        this.latch = latch;
    }

    int tally = 0;
    @Override
    public void run() {

        for(int i = 0; i< 100; i++) {
            tally++;
        }
        latch.countDown();
        System.out.println("Tally is " + tally);

    }

    public int getTally() {
        return tally;
    }
}
List things=new ArrayList(); AtomicInteger总计=新的AtomicInteger(0); 对于(int i=0;i<10;i++){ DoThing DoThing=新的DoThing(闩锁); 添加(点滴); 螺纹=新螺纹(圆点); thread.start(); total.addAndGet(doThing.gettaly()); } //等待所有线程完成。 //每个线程都会对闩锁进行计数 等待 int-total=0; //完成所有线程后计算总和。 为了(溺爱的事物:事物){ total+=thing.gettaly(); } 系统输出打印项次(总计); 类DoThing实现可运行{ 私人倒计时闩锁; 公共点滴(倒计时闩锁){ this.latch=闩锁; } 整数=0; @凌驾 公开募捐{ 对于(int i=0;i<100;i++){ 理货++; } 倒计时(); System.out.println(“理货是”+理货); } 公共int gettaly(){ 返回理货; } }
试试这个:

public static void main(String args[]) {
    AtomicInteger tally = new AtomicInteger(0);
    List<Thread> threadList = new ArrayList<Thread>();
    for (int i = 0; i < 10; i++) {
        Thread t = new Thread(new DoThing(tally));
        t.start();
        threadList.add(t);
    }
    for (Thread t : threadList) {
        try { t.join(); } catch (Exception e){}
    }
    System.out.println("Total tally: " + tally.get());
}

public static class DoThing implements Runnable {
    private static final Random rand = new Random();
    private final AtomicInteger tally;

    public DoThing(AtomicInteger tally) {
        this.tally = tally;
    }

    @Override public void run() {
        for (int i = 0; i < 100; i++) {
            int currTally  = tally.incrementAndGet();
            System.out.println("Thread " + Thread.currentThread().getName() + ": " + currTally);
            // Random sleep to show that your threads are properly concurrently incrementing
            try { Thread.sleep(rand.nextInt(10)); } catch (Exception e) {}
        }
    }
}
publicstaticvoidmain(字符串参数[]){
AtomicInteger Tall=新的AtomicInteger(0);
List threadList=new ArrayList();
对于(int i=0;i<10;i++){
螺纹t=新螺纹(新圆点(计数));
t、 start();
添加(t);
}
对于(线程t:线程列表){
尝试{t.join();}捕获(异常e){}
}
System.out.println(“总计数:+tally.get());
}
公共静态类DoThing实现可运行{
私有静态最终随机兰德=新随机();
私人最终原子计数;
公共点滴(原子整数){
this.tally=理货;
}
@重写公共无效运行(){
对于(int i=0;i<100;i++){
int currTally=tally.incrementAndGet();
System.out.println(“线程”+Thread.currentThread().getName()+”:“+currTally”);
//随机睡眠以显示线程正确地同时递增
尝试{Thread.sleep(rand.nextInt(10));}catch(异常e){}
}
}
}
问题的根源在于您误解了如何使用
AtomicInteger
,您将其视为正常的
int
,并且根本无法同时访问它

另外,在通过调用
thread.join()
确保线程已完成之前,
gettaly()
也是一个争用条件


因此,您可以通过让线程中的所有
Runnable
s更新相同的
AtomicInteger
实例来保持最新的计数,并且您可以通过等待所有线程通过
join()完成计数来确保总数正确
join只需按顺序运行所有线程,即可终止所有多线程处理。

join将根据您的操作方式终止所有多线程处理。@ekaerovets。您可以创建一个线程数组,启动所有线程,然后遍历该数组并在每个线程上调用jointhread@ekaerovets,没有,因为我建议使用两个循环。一个用于启动线程,将每个线程保存在一个列表中,然后第二个循环将它们全部连接起来。@Ivan是的,这是有意义的。我没有考虑过。这会起作用,但它忽略了关于如何使用
AtomicInteger
的误解。您需要等到线程完成任务后再调用
doThings.gettaly()
如果你解释一下,而不是仅仅为他(或她)做那家伙(或杜德特)的家庭作业,这将是一个更好的答案。@jameslarge,也许吧。我认为这个例子是不言自明的,我个人更喜欢几行代码而不是解释。不过,如果这是一个家庭作业,你是对的。非常感谢!这不是家庭作业。只是在做点什么。这非常有用。它不会打印0吗?在请求最终结果之前,您不需要等待所有已启动的线程完成吗?抱歉,打印总计数是一个剩余值。是的,您应该连接所有线程以获得最终结果,但在本例中,这并不重要,因为每个线程每次递增计数时都会打印。我已经添加了加入线程的代码。同意,这是
public static void main(String args[]) {
    AtomicInteger tally = new AtomicInteger(0);
    List<Thread> threadList = new ArrayList<Thread>();
    for (int i = 0; i < 10; i++) {
        Thread t = new Thread(new DoThing(tally));
        t.start();
        threadList.add(t);
    }
    for (Thread t : threadList) {
        try { t.join(); } catch (Exception e){}
    }
    System.out.println("Total tally: " + tally.get());
}

public static class DoThing implements Runnable {
    private static final Random rand = new Random();
    private final AtomicInteger tally;

    public DoThing(AtomicInteger tally) {
        this.tally = tally;
    }

    @Override public void run() {
        for (int i = 0; i < 100; i++) {
            int currTally  = tally.incrementAndGet();
            System.out.println("Thread " + Thread.currentThread().getName() + ": " + currTally);
            // Random sleep to show that your threads are properly concurrently incrementing
            try { Thread.sleep(rand.nextInt(10)); } catch (Exception e) {}
        }
    }
}