JAVA,在多线程中使用LongAdder时得到了错误的值

时间:2018-06-26 11:36:25

标签: java

我正在做这个练习:

  

生成1,000个线程,每个线程增加一个计数器            十万次比较使用AtomicLong的性能            与LongAdder。

以下是我的实现:

import java.io.*;
import java.util.*;
import java.nio.file.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class AtomicLongVsLongAddr {

    // 9. Generate 1,000 threads, each of which increments a counter
    // 100,000 times. Compare the performance of using AtomicLong
    // versus LongAdder.

    AtomicLong al = new AtomicLong(0);
    LongAdder la = new LongAdder();

    public class AtomicLongThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100000; i ++) {
                al.incrementAndGet();
            }
        }
    }

    public class LongAdderThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100000; i ++) {
                la.increment();
            }
        }
    }

    public static void main(String[] args) {
        AtomicLongVsLongAddr vs = new AtomicLongVsLongAddr();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i ++) {
            (vs.new AtomicLongThread()).start();
        }
        long endTime = System.currentTimeMillis();
        System.out.printf("AtomicLong--Number: %s, Time: %d\n", vs.al, endTime - startTime);
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i ++) {
            (vs.new LongAdderThread()).start();
        }
        long res = vs.la.sum();
        endTime = System.currentTimeMillis();
        System.out.printf("LongAdder--Number: %s, Time: %d\n", res, endTime - startTime);

    }

}

每次运行此程序时,我都会得到以下内容作为标准输出:

AtomicLong--Number: 100000000, Time: 2330
LongAdder--Number: 99882179, Time: 469

很明显,我对LongAdder的值有误,但是我无法弄清楚哪里做错了。

你能帮我吗?

已更新

在这里所有人和@Ravindra Ranwala的帮助下,我更新了上面练习的答案:

import java.io.*;
import java.util.*;
import java.nio.file.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class AtomicLongVsLongAddr {

    // 9. Generate 1,000 threads, each of which increments a counter
    // 100,000 times. Compare the performance of using AtomicLong
    // versus LongAdder.

    AtomicLong al = new AtomicLong(0);
    LongAdder la = new LongAdder();

    public class AtomicLongThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100000; i ++) {
                al.incrementAndGet();
            }
        }
    }

    public class LongAdderThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100000; i ++) {
                la.increment();
            }
        }
    }

    public static void main(String[] args) {
        try{
            long startTime;
            long endTime;
            AtomicLongVsLongAddr vs = new AtomicLongVsLongAddr();
            Thread[] t = new Thread[1000];
            for (int i = 0; i < 1000; i ++) {
                t[i] = vs.new AtomicLongThread();
            }
            startTime = System.currentTimeMillis();
            for (int i = 0; i < 1000; i ++) {
                t[i].start();
                t[i].join();
            }
            endTime = System.currentTimeMillis();
            System.out.printf("AtomicLong--Number: %s, Time: %d\n", vs.al, endTime - startTime);
            for (int i = 0; i < 1000; i ++) {
                t[i] = vs.new LongAdderThread();
            }
            startTime = System.currentTimeMillis();
            for (int i = 0; i < 1000; i ++) {
                t[i].start();
                t[i].join();
            }
            long res = vs.la.sum();
            endTime = System.currentTimeMillis();
            System.out.printf("LongAdder--Number: %s, Time: %d\n", res, endTime - startTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果仍然有任何错误,请为我指出。谢谢大家。

2 个答案:

答案 0 :(得分:6)

在所有线程上调用Thread.join,然后等待它们全部完成。看来您的主线程在其他增加两个变量的线程之前退出了。您得到的是一些中间结果。

这是代码,

public static void main(String[] args) throws InterruptedException {
    final List<Thread> adderThreads = new ArrayList<>();
    final List<Thread> atomicThreads = new ArrayList<>();
    AtomicLongVsLongAddr vs = new AtomicLongVsLongAddr();
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++) {
        final AtomicLongThread atomicThread = vs.new AtomicLongThread();
        atomicThreads.add(atomicThread);
        atomicThread.start();
    }

    for (Thread thread : atomicThreads) {
        thread.join();
    }
    long endTime = System.currentTimeMillis();
    System.out.printf("AtomicLong--Number: %s, Time: %d\n", vs.al, endTime - startTime);
    startTime = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++) {
        final LongAdderThread adderThread = vs.new LongAdderThread();
        adderThreads.add(adderThread);
        adderThread.start();
    }
    for (Thread thread : adderThreads) {
        thread.join();
    }
    long res = vs.la.sum();
    endTime = System.currentTimeMillis();
    System.out.printf("LongAdder--Number: %s, Time: %d\n", res, endTime - startTime);

}

答案 1 :(得分:1)

您的代码不是同步的-主线程将在完成计数器线程之前退出/继续,从而产生差异。