加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

如果由线程修改的变量标记为volatile,为什么false共享问题

发布时间:2020-12-15 03:01:54 所属栏目:Java 来源:网络整理
导读:我一直在看Martin Thompson的文章.这是对虚假分享的解释. http://mechanical-sympathy.blogspot.co.uk/2011/07/false-sharing.html public final class FalseSharing implements Runnable { public final static int NUM_THREADS = 4; // change public fina
我一直在看Martin Thompson的文章.这是对虚假分享的解释.

http://mechanical-sympathy.blogspot.co.uk/2011/07/false-sharing.html

public final class FalseSharing
    implements Runnable
    {
        public final static int NUM_THREADS = 4; // change
        public final static long ITERATIONS = 500L * 1000L * 1000L;
        private final int arrayIndex;

        private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];


        static
        {    
            for (int i = 0; i < longs.length; i++)
            {
                longs[i] = new VolatileLong();
            }
        }

        public FalseSharing(final int arrayIndex)
        {
            this.arrayIndex = arrayIndex;
        }

        public static void main(final String[] args) throws Exception
        {
            final long start = System.nanoTime();
            runTest();
            System.out.println("duration = " + (System.nanoTime() -start));
        }

        private static void runTest() throws InterruptedException
        {
            Thread[] threads = new Thread[NUM_THREADS];

            for (int i = 0; i < threads.length; i++)
            {
                threads[i] = new Thread(new FalseSharing(i));
            }

            for (Thread t : threads)
            {
                t.start();
            }

            for (Thread t : threads)
            {
                t.join();
            }
        }

        public void run()
        {
            long i = ITERATIONS + 1;
            while (0 != --i)
            {
                longs[arrayIndex].value = i;
            }
        }

        public final static class VolatileLong
        {
            public volatile long value = 0L;
            public long p1,p2,p3,p4,p5,p6; // comment out
        }
    }

该示例演示了多个线程使彼此的高速缓存行无效所经历的减速,即使每个线程仅仅更新一个变量.

BlockqFigure 1. above illustrates the issue of false sharing. A thread running on core 1 wants to update variable X while a thread on core 2 wants to update variable Y. Unfortunately these two hot variables reside in the same cache line. Each thread will race for ownership of the cache line so they can update it. If core 1 gets ownership then the cache sub-system will need to invalidate the corresponding cache line for core 2. When Core 2 gets ownership and performs its update,then core 1 will be told to invalidate its copy of the cache line. This will ping pong back and forth via the L3 cache greatly impacting performance. The issue would be further exacerbated if competing cores are on different sockets and additionally have to cross the socket interconnect.

我的问题如下.如果要更新的所有变量都是易失性的,为什么这个填充会导致性能提升?我的理解是,volatile变量总是写入并读取到主存储器.因此,我假设在此示例中对任何变量的每次写入和读取都将导致当前核心高速缓存行的刷新.

所以根据我的理解.如果线程1使线程二的高速缓存行无效,那么在它从其自己的高速缓存行读取值之前,这将不会成为线程2的替代.它读取的值是一个易失性值,因此这有效地使缓存变脏,从而导致从主存储器读取.

我的理解在哪里出错了?

谢谢

解决方法

If all the variables being updated are volatile,why does this padding cause a performance increase?

所以这里有两件事:

>我们正在处理一系列VolatileLong对象,每个线程都在自己的VolatileLong上工作. (参见private final int arrayIndex).
>每个VolatileLong对象都有一个volatile字段.

易失性访问意味着线程必须使保持其volatile变长值的cache “line”无效,并且需要锁定该缓存行以更新它.正如文章所述,缓存行通常约为64字节左右.

文章说通过向VolatileLong对象添加填充,它将每个线程锁定的对象移动到不同的缓存行中.因此,即使不同的线程在分配其易失性长值时仍然跨越内存屏障,它们处于不同的高速缓存行中,因此不会导致过多的L2高速缓存带宽.

总之,性能提升的原因在于,即使线程仍然锁定其缓存行以更新volatile字段,这些锁现在位于不同的内存块上,因此它们不会与其他线程的锁冲突并导致缓存失效.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读