我通过比较同步方法来测试多线程中的原子整数有多快,但我得到的结果是原子整数比同步方法慢。
我阅读了 Java API 引用,我了解到 Atomic Integer 在多线程中比同步更快。
所以我想知道我使用 Atomic Integer 得到糟糕结果的原因。 我的测试代码错了吗?
这是我的代码
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicThreadTest {
// Number of thread to run
private static final int THREAD_NUM = 1000;
// Repetition number to count up
private static final int ROOP_NUM = 200000;
// Base counter class
private abstract class Counter implements Runnable {
@Override
public void run() {
for (int i = 0; i < ROOP_NUM; i++) {
increment();
}
}
// Increment method
public abstract void increment();
// Get result of calculation
public abstract int getResult();
// Get name of the class
@Override
public String toString() {
return getClass().getSimpleName();
}
}
// Use no thread safe
private static int count = 0;
private class NoThreadSafeCounter extends Counter {
@Override
public void increment() {
count++;
}
@Override
public int getResult() {
return count;
}
}
// Use volatile
private static volatile int volatileCount = 0;
private class VolatileCounter extends Counter {
@Override
public void increment() {
volatileCount++;
}
@Override
public int getResult() {
return volatileCount;
}
}
// Use synchronized
private static int synchronizedCount = 0;
private class SynchronizedCounter extends Counter {
@Override
public synchronized void increment() {
synchronizedCount++;
}
@Override
public int getResult() {
return synchronizedCount;
}
}
// Use AtomicInteger
private static AtomicInteger atomicCount = new AtomicInteger(0);
private class AtomicCounter extends Counter {
@Override
public void increment() {
atomicCount.incrementAndGet();
}
@Override
public int getResult() {
return atomicCount.get();
}
}
public static void main(String[] args) {
AtomicThreadTest testClass = new AtomicThreadTest();
Counter[] testCounter = {
testClass.new NoThreadSafeCounter(),
testClass.new VolatileCounter(),
testClass.new SynchronizedCounter(),
testClass.new AtomicCounter(),
};
for (Counter c : testCounter) {
System.out.println("-------------------------");
System.out.printf("Test for class : %s\n", c.toString());
try {
test(c);
} catch (InterruptedException e) {
System.out.println("Test halted");
} finally {
System.out.println("");
System.gc();
}
}
System.out.println("-------------------------");
}
public static void test(final Counter counter) throws InterruptedException {
System.out.printf("Start with threads : %d, roop : %d\n", THREAD_NUM, ROOP_NUM);
final long startTime = System.currentTimeMillis();
// Create THREAD_NUM threads and run them
Thread[] threads = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++) {
threads[i] = new Thread(counter);
threads[i].start();
}
// Wait for all threads other than this end
while (Thread.activeCount() > 1) {
Thread.sleep(10);
}
final long endTime = System.currentTimeMillis();
System.out.printf("Result %d, Expected %d\n", counter.getResult(), THREAD_NUM*ROOP_NUM);
System.out.printf("Time to calc : %d\n", endTime-startTime);
}
}
我得到了下面的结果。
-------------------------
Test for class : NoThreadSafeCounter
Start with threads : 1000, roop : 200000
Result 198785583, Expected 200000000
Time to calc : 127
-------------------------
Test for class : VolatileCounter
Start with threads : 1000, roop : 200000
Result 19162116, Expected 200000000
Time to calc : 4458
-------------------------
Test for class : SynchronizedCounter
Start with threads : 1000, roop : 200000
Result 200000000, Expected 200000000
Time to calc : 8426
-------------------------
Test for class : AtomicCounter
Start with threads : 1000, roop : 200000
Result 200000000, Expected 200000000
Time to calc : 15190
最佳答案
抛开你的测试用例的代码问题,让我们谈谈多线程问题本身。
如果你设置THREAD_NUM
到更小的数字,例如 8 或 4,您会发现您的 AtomicCounter
比 SynchronizedCounter
快一点.在 AtomicInteger
上运行 1000 个线程将花费两倍的 CPU的 CAS(比较和交换),这导致它运行得比 synchronized
慢代码块。
为了证明这一点,您可以实现 LongadderCounter
:
private class LongadderCounter extends Counter {
@Override
public void increment() {
longadder.increment();
}
@Override
public int getResult() {
return longadder.intValue();
}
}
你会发现 LongadderCounter
快多了。 LongAdder
至 AtomicInteger
是ConcurrentHashMap
至 Collections.synchronizedMap(new HashMap<>())
,它将计数器分成多个部分,并对每个部分进行 CAS 以缓解竞争条件。
关于java - AtomicInteger 比同步慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422441/