Thread safety issues

Keywords: Attribute jvm Java

In the previous section, we mainly talked about the JVM memory model and the visibility of thread safety. This section focuses on the atomic operation of thread safety;

Competitive condition and critical region

Code example

public class IncrDemo {
    public int i = 0;
    public void incr() {
        i++;	//Critical area
    }
}

shared resource

Immutable object

Atomic operation definition

CAS mechanism


J. Atomic operation encapsulation class in U.C package

Thread safe code example

volatile thread safety example:

public class LockDemo1 {
    volatile int value = 0;

    // Direct operation of memory, modification of objects, array memory.... powerful API
    static Unsafe unsafe;
    private static long valueOffset;

    static {
        try {
            // Obtaining unsafe value by reflection technique
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);

            // Get the value attribute offset (used to determine the specific address of the value attribute in memory)
            valueOffset = unsafe.objectFieldOffset(LockDemo1.class.getDeclaredField("value"));

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void add() {
        // TODO xx00
        // i++;// JAVA level three steps
        // CAS + loop retry
        int current;
        do {
            // If the operation is time-consuming, the thread will take up a lot of CPU execution time
            current = unsafe.getIntVolatile(this, valueOffset);
        } while (!unsafe.compareAndSwapInt(this, valueOffset, current, current + 1));
        // May fail
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo1 ld = new LockDemo1();

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    ld.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(ld.value);
    }
}

Example of synchronized thread safety:

public class LockDemo2 {
    int i = 0;

    public void add() {
        synchronized (this) {
            i++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo2 ld = new LockDemo2();
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    ld.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(ld.i);
    }
}

Lock thread safety example:

public class LockDemo3 {
    volatile int i = 0;

    Lock lock = new ReentrantLock();

    public void add() {
        lock.lock();
        try {
            i++;
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo3 ld = new LockDemo3();

        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    ld.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(ld.i);
    }
}

Example of atomic thread safety:

public class LockDemo4 {
    // volatile int i = 0;
    AtomicInteger i = new AtomicInteger(0);

    public void add() {
        // TODO xx00
        // i + +; / / three steps
        i.incrementAndGet();
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo4 ld = new LockDemo4();

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    ld.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(ld.i);
    }
}

Comparison of thread safety operation efficiency

// Test case: run for 2 seconds at the same time, and check who has the most times
public class LongAdderDemo {
    private long count = 0;

    // How to synchronize code blocks
    public void testSync() throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                long starttime = System.currentTimeMillis();
                while (System.currentTimeMillis() - starttime < 2000) { // Run for two seconds.
                    synchronized (this) {
                        ++count;
                    }
                }
                long endtime = System.currentTimeMillis();
                System.out.println("SyncThread spend:" + (endtime - starttime) + "ms" + " v" + count);
            }).start();
        }
    }

    // Atomic mode
    private AtomicLong acount = new AtomicLong(0L);

    public void testAtomic() throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                long starttime = System.currentTimeMillis();
                while (System.currentTimeMillis() - starttime < 2000) { // Run for two seconds.
                    acount.incrementAndGet(); // acount++;
                }
                long endtime = System.currentTimeMillis();
                System.out.println("AtomicThread spend:" + (endtime - starttime) + "ms" + " v-" + acount.incrementAndGet());
            }).start();
        }
    }

    // LongAdder mode
    private LongAdder lacount = new LongAdder();
    public void testLongAdder() throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                long starttime = System.currentTimeMillis();
                while (System.currentTimeMillis() - starttime < 2000) { // Run for two seconds.
                    lacount.increment();
                }
                long endtime = System.currentTimeMillis();
                System.out.println("LongAdderThread spend:" + (endtime - starttime) + "ms" + " v-" + lacount.sum());
            }).start();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LongAdderDemo demo = new LongAdderDemo();
        demo.testSync();
        demo.testAtomic();
        demo.testLongAdder();
    }
}

Console output (random):

SyncThread spend:2000ms v24158152
SyncThread spend:2000ms v24158151
SyncThread spend:2000ms v24184392
AtomicThread spend:2000ms v-112956795
AtomicThread spend:2000ms v-112956796
AtomicThread spend:2000ms v-112956797
LongAdderThread spend:2000ms v-151089455
LongAdderThread spend:2000ms v-151089455
LongAdderThread spend:2000ms v-151089455
Published 8 original articles, praised 0, visited 507
Private letter follow

Posted by kingconnections on Fri, 07 Feb 2020 06:15:14 -0800