Why is Java’s exchange Slot cache line fill like this?

When I read the 'false sharing' mechanism in Java, I was in Java util. concurrent. Exchanger. The following code is found in slot

/**
 * A Slot is an AtomicReference with heuristic padding to lessen
 * cache effects of this heavily CAS'ed location.  While the
 * padding adds noticeable space,all slots are created only on
 * demand,and there will be more than one of them only when it
 * would improve throughput more than enough to outweigh using
 * extra space.
 */
private static final class Slot extends AtomicReference<Object> {
    // Improve likelihood of isolation on <= 64 byte cache lines
    long q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,qa,qb,qc,qd,qe;
}

It's strange Why is the long number 15 (Q0 QE), so I can calculate that the size of the object should be: 15 * 8 (long) 8 (long value of the parent value) 16 (object header pointer of 64 bit JVM) = 144 bytes Either: 15 * 8 (long) 8 (long value of parent) 8 (object header pointer of 32-bit JVM) = 136 bytes When I read about disruptor's implementation:

public long p1,p2,p3,p4,p5,p6,p7; // cache line padding

private volatile long cursor = INITIAL_CURSOR_VALUE;

public long p8,p9,p10,p11,p12,p13,p14; // cache line padding

Size should be 7 * 8 7 * 8 8 (object header operation size is 32-bit JVM) = 128 = 64 * 2 Since the default cache line size of most CPUs is 64 bytes, the impl of discriminator can avoid 'false sharing' So my question is the number of Java util. concurrent. Exchanger. Is slot right or wrong?

Solution

java. util. concurrent. Exchanger. The fill in slot is playing safely It's adding extra padding, while the destroyer, on the other hand, is adding enough

If the JVM reorders fields and the cache row size is 128 bits, the destructor method may also fail The safest way is to separate fields through inheritance:

class MemoryFieldAddress {
    private long address;

    public final long getAddress() {
        return address;
    }

    protected final void setAddress(final long address) {
        this.address = address;
    }
}

class MemoryAddressPad1 extends MemoryFieldAddress {
    long p1_1,p1_2,p1_3,p1_4,p1_5,p1_6,p1_7,p1_8,p1_9,p1_10,p1_11,p1_12,p1_13,p1_14,p1_15,p1_16,p1_17;
}

class MemoryFieldBytes extends MemoryAddressPad1 {
    private long bytes;

    public final long getBytes() {
        return bytes;
    }

    protected final void setBytes(final long bytes) {
        this.bytes = bytes;
    }
}

class MemoryAddressPad2 extends MemoryFieldBytes {
    long p2_1,p2_2,p2_3,p2_4,p2_5,p2_6,p2_7,p2_8,p2_9,p2_10,p2_11,p2_12,p2_13,p2_14,p2_15,p2_16,p2_17;
}

// Finally the full implimentation
public class Memory extends MemoryAddressPad2 {}

If necessary, you can calculate the final field and rarely update the field towards filling

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>