Java 当AtomicInteger比synchronized快时

Java 当AtomicInteger比synchronized快时,java,concurrency,synchronization,volatile,atomicinteger,Java,Concurrency,Synchronization,Volatile,Atomicinteger,我已经读过很多文章,其中提到AtomicInteger类比同步构造工作得更快。我在AtomicInteger和“synchronized”上做了一些测试,在我的测试中,synchronized比AtomicInteger快得多。我想了解出了什么问题:我的测试类不正确,或者AtomicInteger在其他情况下工作得更快? 这是我的测试课: public class Main { public static void main(String[] args) throws Inte

我已经读过很多文章,其中提到AtomicInteger类比同步构造工作得更快。我在AtomicInteger和“synchronized”上做了一些测试,在我的测试中,synchronized比AtomicInteger快得多。我想了解出了什么问题:我的测试类不正确,或者AtomicInteger在其他情况下工作得更快?

这是我的测试课:

    public class Main {

    public static void main(String[] args) throws InterruptedException
    {
        // creating tester "synchronized" class
        TesterSynchronized testSyn = new TesterSynchronized();

        // Creating 3 threads
        Thread thread1 = new Thread(testSyn);
        Thread thread2 = new Thread(testSyn);
        Thread thread3 = new Thread(testSyn);

        // start time
        long beforeSyn = System.currentTimeMillis();

        // start
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();

        long afterSyn = System.currentTimeMillis();
        long delta = afterSyn - beforeSyn;

        System.out.println("Test synchronized: " + delta + " ms");

        // _______________________________________________________

        // creating tester "atomicInteger" class
        TesterAtomicInteger testAtomic = new TesterAtomicInteger();

        thread1 = new Thread(testAtomic);
        thread2 = new Thread(testAtomic);
        thread3 = new Thread(testAtomic);

        // start time
        long beforeAtomic = System.currentTimeMillis();

        // start
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();

        long afterAtomic = System.currentTimeMillis();
        long deltaAtomic = afterAtomic - beforeAtomic;

        System.out.println("Test atomic integer: " + deltaAtomic + " ms");
    }
}

// Synchronized tester
class TesterSynchronized implements Runnable {
    public int integerValue = 0;

    public synchronized void run() {
        for (int i = 0; i < 1_000_000; i++)
            integerValue++;
    }
}

// AtomicInteger class tester
class TesterAtomicInteger implements Runnable {
    AtomicInteger atomicInteger = new AtomicInteger(0);

    public void run() {
        for (int i = 0; i < 1_000_000; i++)
            atomicInteger.incrementAndGet();
    }
}
公共类主{
公共静态void main(字符串[]args)引发InterruptedException
{
//创建tester“synchronized”类
TesterSynchronized testSyn=新的TesterSynchronized();
//创建3个线程
螺纹螺纹1=新螺纹(testSyn);
螺纹2=新螺纹(testSyn);
螺纹3=新螺纹(testSyn);
//开始时间
long beforeSyn=System.currentTimeMillis();
//开始
thread1.start();
thread2.start();
thread3.start();
thread1.join();
螺纹2.连接();
螺纹3.连接();
long afterSyn=System.currentTimeMillis();
长增量=后同步-前同步;
System.out.println(“测试同步:+delta+“ms”);
// _______________________________________________________
//创建tester“atomicInteger”类
TesterAtomicInteger testAtomic=新的TesterAtomicInteger();
thread1=新线程(testAtomic);
螺纹2=新螺纹(testAtomic);
thread3=新线程(testAtomic);
//开始时间
long beforeaomic=System.currentTimeMillis();
//开始
thread1.start();
thread2.start();
thread3.start();
thread1.join();
螺纹2.连接();
螺纹3.连接();
long afterAtomic=System.currentTimeMillis();
长deltaAtomic=后原子-前原子;
System.out.println(“测试原子整数:“+deltaAtomic+”ms”);
}
}
//同步测试仪
类TesterSynchronized实现可运行{
公共整数整数值=0;
公共同步的无效运行(){
对于(int i=0;i<1_000;i++)
integerValue++;
}
}
//原子整数类测试器
类TesterAtomicIntegrater实现Runnable{
AtomicInteger AtomicInteger=新的AtomicInteger(0);
公开募捐{
对于(int i=0;i<1_000;i++)
atomicInteger.incrementAndGet();
}
}
测试参数:3个线程,增量为1_000_000; 结果:

测试同步:7毫秒。测试原子整数:51毫秒

我很高兴了解为什么会发生这种情况。

UPD 如果将同步方法更改为同步块,则测试将是正确的

//同步测试仪
类TesterSynchronized实现可运行{
公共整数整数值=0;
公开募捐{
对于(int i=0;i<1_000;i++){
已同步(此){
integerValue++;
}
}
}
}

代码中的明显区别在于,
AtomicIntger
版本允许线程的交叉访问,而
synchronized
版本则依次对每个线程执行整个循环


可能还有其他问题。例如,JVM可以合并一个
同步的
块的多个调用。根据平台的不同,
incrementAndGet
可能不是一个原子操作,而是作为CAS循环实现的-如果争用很高,这可能是一个问题(我不完全确定)


无论以何种方式排列,如果您有多个线程同时修改同一内存位置,那么速度都不会很快。

代码中的明显区别在于,
AtomicIntger
版本允许线程交叉访问,而
synchronized
版本则依次对每个线程执行整个循环


可能还有其他问题。例如,JVM可以合并一个
同步的
块的多个调用。根据平台的不同,
incrementAndGet
可能不是一个原子操作,而是作为CAS循环实现的-如果争用很高,这可能是一个问题(我不完全确定)


无论采用哪种方式,如果多个线程同时修改同一内存位置,速度都不会很快。

在同步测试仪中,您只需锁定一个锁,然后执行百万次增量。在AtomicInteger示例中,您正在为每个增量获取并释放一个锁。尝试将
synchronized
包装在
integerValue++
周围,
AtomicInteger
将更快。你无法比较这两种方法。事实上,这是一个问题!更改为synchronized block后,测试结果为:test synchronized:244 ms test atomic integer:95 ms。除了
synchronized
中的错误外,您还应该检查如何执行。在这里的这个测试中,
synchronized
可能比较慢,但在其他一些测试中,您希望避免影响结果的噪音。原始的TesterSynchronized循环可以由编译器优化。执行这个循环没有意义;它可以立即将1_000_000分配给integerValue,而不是执行1M增量。在同步测试仪中,您只需执行一个锁,然后执行百万增量。在AtomicInteger示例中,您正在为每个增量获取并释放一个锁。尝试将
synchronized
包装在
integerValue++
周围,
AtomicInteger
将更快。你无法比较这两种方法。事实上,这是一个问题!更改为synchronized block后,测试结果为:test synchronized:244 ms test atomic integer:95 ms。除了
synchronized
中的错误外,您还应该检查如何执行。在这里的测试中,可能很清楚
// Synchronized tester
class TesterSynchronized implements Runnable {
    public int integerValue = 0;

    public void run() {
        for (int i = 0; i < 1_000_000; i++) {
            synchronized (this) {
                integerValue++;
            }
        }
    }
}