1

在JDK11中编译运行,看看结果。sum1 是同步代码所用的时间,而 sum2 是 AtomicInteger 代码所用的时间。count1 是对同步 count++ 的调用次数进行计数的结果。count2 是相同数量的组合调用,但使用 AtomicInteger。计数应为 2000000,并且预计 sum1 > sum2 以 ms 为单位。但是,count1 明显减少了,那么电话会去哪里呢?

github

package com.charlie;

import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicTest extends Thread{

    private volatile Integer count1 = 0;
    private AtomicInteger count2 = new AtomicInteger(0);
    
    private void method1() {
        for (int i=0; i<1000; i++) {
            int a = i;
        }
        synchronized (count1){
            count1++;
        }
    }    
    private void method2() {
        for (int i=0; i<1000; i++) {
            int a = i;
        }
        count2.getAndIncrement();
    }
    
    public class Thread1 extends Thread{
        public Date start = null;
        public Date stop = null;
        @Override
        public
        void run() {
            start = new Date();
            for(int i=0;i<1000000;i++) {
                method1();
            }
            stop = new Date();
        } 
    }    
    public class Thread3 extends Thread{
        public Date start = null;
        public Date stop = null;
        @Override
        public
        void run() {
            start = new Date();
            for(int i=0;i<1000000;i++) {
                method2();
            }
            stop = new Date();
        } 
    }    
    static Thread1 t1 = null;
    static Thread1 t2 = null;
    static Thread3 t3 = null;
    static Thread3 t4 = null;
    static AtomicTest master = null;

    public static void main(String[] args) {
        AtomicTest master = new AtomicTest();
        t1 = master.new Thread1();
        t2 = master.new Thread1();
        t3 = master.new Thread3();
        t4 = master.new Thread3();
        master.start();
        t1.start();t2.start();t3.start();t4.start();
    }
    
    @Override
    public void run() {
        //stop and sum
        Boolean finished = false;
        while(!finished) {
            try {
                AtomicTest.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(t1.stop != null && t2.stop != null && t3.stop != null && t4.stop != null) {
                Long sum1 = (t1.stop.getTime() - t1.start.getTime()) 
                + (t2.stop.getTime() - t2.start.getTime());
                Long sum2 = (t3.stop.getTime() - t3.start.getTime())
                + (t4.stop.getTime() - t4.start.getTime());
                finished = true;
                System.out.println("sum1 =" + sum1 + "ms sum2 =" + sum2 + "ms");
                System.out.println("count1 =" + count1 + " count2 =" + count2);
            }
        }
    }
}
4

2 回答 2

0

不要在可能重复使用的对象上进行同步。如果您想了解更多信息,请阅读这篇文章。

在您的情况下避免这种情况的一个简单解决方案是用一个空对象锁定。

private Object key = new Object();
private volatile Integer count1 = 0;

private void method1() {
    for (int i=0; i<1000; i++) {
        int a = i;
    }
    synchronized (key){
        count1++;
    }
}    
于 2021-01-11T19:11:54.987 回答
0

Java Integer 是不可变的,因此当您在其上使用 ++ 时,它会创建一个新对象。如果您在这些对象上同步,它们将具有不同的身份,因此这将不起作用。要修复它,您可以将 Integer 更改为纯 int (如果您不需要),但创建一个单独的 Object 进行同步。例如私有对象同步=新对象();从 Integer 更改为 plain int 也应该加快速度。

这项工作更改现在在 github 中。谢谢 Magyar Tamas 和 Jason Splashett。

于 2021-01-26T14:26:07.610 回答