我通过比较同步方法来测试多线程中Atomic Integer的速度有多快,但我得到的结果是Atomic Integer比同步方法慢。
我阅读了Java API Reference,我理解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
答案 0 :(得分:2)
尽管您的测试用例存在代码问题,但请谈谈多线程问题本身。
如果您将AtomicInteger
设置为更低的数字(例如8或4),您会发现synchronized
比LongadderCounter
快一点。使用1000个线程运行将花费private class LongadderCounter extends Counter {
@Override
public void increment() {
longadder.increment();
}
@Override
public int getResult() {
return longadder.intValue();
}
}
的CAS(比较和交换)上的两个CPU,这导致它比LongadderCounter
代码块运行得慢。
为了证明这一点,您可以实施LongAdder
:
AtomicInteger
您会更快地发现ConcurrentHashMap
。 Collections.synchronizedMap(new HashMap<>())
至 var usrInput = usrInput.ToLower();
foreach(var letter in usrInput)
{
if (letter == 'a' || letter == 'b' || letter == 'c')
{
Console.Write("1");
}
else if (letter == 'd' || letter == 'e' || letter == 'f')
{
Console.Write("2");
}
else if (letter == 'g' || letter == 'h' || letter == 'i')
{
Console.Write("3");
}
}
dataimport.properties
至UTC
,它将计数器分为多个部分,并在每个部分执行CAS以减轻竞争条件。