【问题标题】:Synchronized java code performs times faster than unsynchronized one同步的 java 代码执行速度比不同步的快几倍
【发布时间】:2013-05-31 12:47:23
【问题描述】:

我在开发一个高并发应用程序。在应用程序代码中,我尽量避免同步。最近,在比较非同步和同步代码版本的测试性能时,结果显示同步代码的执行速度比非同步代码快三四倍。

经过一些实验,我得出了这个测试代码:

private static final Random RND = new Random();
private static final int NUM_OF_THREADS = 3;
private static final int NUM_OF_ITR = 3;
private static final int MONKEY_WORKLOAD = 50000;

static final AtomicInteger lock = new AtomicInteger();

private static void syncLockTest(boolean sync) {
    System.out.println("syncLockTest, sync=" + sync);

    final AtomicLong jobsDone = new AtomicLong();
    final AtomicBoolean stop = new AtomicBoolean();

    for (int i = 0; i < NUM_OF_THREADS; i++) {
        Runnable runner;

        if (sync) {
            runner = new Runnable() {
                @Override
                public void run() {
                    while (!stop.get()){
                        jobsDone.incrementAndGet();

                        synchronized (lock) {
                            monkeyJob();
                        }

                        Thread.yield();
                    }
                }
            };
        } else {
            runner = new Runnable() {
                @Override
                public void run() {
                    while (!stop.get()){
                        jobsDone.incrementAndGet();

                        monkeyJob();

                        Thread.yield();
                    }
                }
            };
        }

        new Thread(runner).start();
    }

    long printTime = System.currentTimeMillis();

    for (int i = 0; i < NUM_OF_ITR;) {
        long now = System.currentTimeMillis();
        if (now - printTime > 10 * 1000) {
            printTime = now;
            System.out.println("Jobs done\t" + jobsDone);
            jobsDone.set(0);
            i++;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    stop.set(true);
}

private static double[] monkeyJob() {
    double[] res = new double[MONKEY_WORKLOAD];
    for (int i = 0; i < res.length; i++) {
        res[i] = RND.nextDouble();
        res[i] = 1./(1. + res[i]);
    }
    return res;
}

我考虑了线程数、工作负载、测试迭代 - 每次同步代码的执行速度都比非同步代码快得多。

这是 NUM_OF_THREADS 的两个不同值的结果

线程数:3
syncLockTest, sync=true
Jobs 完成 5951
完成任务 5958
完成任务 5878
syncLockTest, sync=false
已完成的工作 1399
已完成的工作 1397
已完成的工作 完成 1391

线程数:5
syncLockTest,sync=true
完成 5895
完成工作 6464
完成工作 5886
syncLockTest, sync=false
已完成的工作 1179
已完成的工作 1260
已完成的工作 完成 1226

测试环境 视窗 7 专业版 Java 7.0 版

这是一个类似的案例Synchronized code performs faster than unsynchronized one

有什么想法吗?

【问题讨论】:

标签: java concurrency synchronization


【解决方案1】:

Random 是一个线程安全的类。您很可能通过围绕主要作业进行同步来避免对 Random 类的调用的争用。

【讨论】:

  • +2 你是对的!在使 rnd 成为局部变量后,未同步的代码按预期执行。非常感谢!
【解决方案2】:

这很有趣。我认为@jtahlborn 做到了。如果我移动 Random 并将其设置为线程本地,则非同步跳转的时间约为 10 倍,而 synchronized 的时间不会改变:

这是我与static Random RND 相处的时间:

syncLockTest, sync=true
Jobs done   8800
Jobs done   8839
Jobs done   8896
syncLockTest, sync=false
Jobs done   1401
Jobs done   1381
Jobs done   1423

这是我每个线程都有一个 Random rnd 局部变量的时间:

syncLockTest, sync=true
Jobs done   8846
Jobs done   8861
Jobs done   8866
syncLockTest, sync=false
Jobs done   25956   << much faster
Jobs done   26065   << much faster
Jobs done   26021   << much faster

我还想知道这是否与 GC 有关,但是将 double[] res 移动到本地线程并没有帮助提高速度。这是我使用的代码:

...
@Override
public void run() {
    // made this be a thread local but it affected the times only slightly
    double[] res = new double[MONKEY_WORKLOAD];
    // turned rnd into a local variable instead of static
    Random rnd = new Random();
    while (!stop.get()) {
        jobsDone.incrementAndGet();
        if (sync) {
            synchronized (lock) {
                monkeyJob(res, rnd);
            }
        } else {
            monkeyJob(res, rnd);
        }
    }
}
...

private static double[] monkeyJob(double[] res, Random rnd) {
    for (int i = 0; i < res.length; i++) {
        res[i] = rnd.nextDouble();
        res[i] = 1. / (1. + res[i]);
    }
    return res;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    相关资源
    最近更新 更多