The last article explained the basic usage and general principles of AtomicInteger, have you learned?

Anyone who has read this article will be familiar with AtomicInteger.

So today we’re going to look at another atomic class: AtomicBoolean

Introduction to the

AtomicBoolean provides a solution for atomically reading and writing Boolean variables. Typically, this class will be used to atomically update status flag bits, such as: flag.

AtomicInteger is a volatile Boolean attribute. AtomicInteger is a volatile Boolean attribute. AtomicInteger is a volatile Boolean attribute.

Let’s take a look at the source code:

public class AtomicBoolean implements java.io.Serializable {
    private static final long serialVersionUID = 4654671469794556979L;

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    private static final long valueOffset;
    // Volatile modifythe value attribute of int
    private volatile int value;
}
Copy the code

What’s going on?

And AtomicInteger!

Smart readers must have known that before! At first I thought it should be a Boolean property, but I can’t guess until I actually look at it.

How did that become booleans?

Let’s look at AtomicBoolean constructors and CAS core methods:

public AtomicBoolean(boolean initialValue) {
    value = initialValue ? 1 : 0;
}

public final boolean compareAndSet(boolean expect, boolean update) {
    int e = expect ? 1 : 0;
    int u = update ? 1 : 0;
    return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
Copy the code

Now look at the get method:

public final boolean get(a) {
    returnvalue ! =0;
}
Copy the code

Is there a feeling of clearing the clouds and seeing the sky? It turns out that it is converted into int type by combining trisome operation, and then uses the native method unsafe.compareAndSwapInt to achieve the result we want.

Basic usage

The basic usage of method, which I won’t explain in detail here, is basically the same as AtomicInteger.

Well, let’s call it a day!

HMM… That’s impossible. How can it be so short? You haven’t even had a good time yet.

In actual combat

In the previous article, we addressed the thread safety of i++, using the synchronized keyword and display Lock. However, when comparing their performance, we found that their performance is very different. BLOCKED threads of synchronized occupy too high a proportion, and locked WAITING threads occupy a relatively high proportion, but do not occupy too much CPU resources.

The reason is that when the synchronized keyword is used to compete for the lock, the thread that does not compete for the Monitor Enter will Enter the blocking state, and it is a kind of uninterruptible blocking. The thread can only continue to compete after the thread that holds the lock releases the Monitor.

This article uses AtomicBoolean to implement a simple non-blocking Lock:

public class BooleanLock {

    /**
     * 全局标志位
     */
    private final AtomicBoolean flag = new AtomicBoolean(false);

    /** * Store data copy */
    private final ThreadLocal<Boolean> threadLocal = ThreadLocal.withInitial(() -> false);

    /** * Attempts to obtain the lock */
    public boolean tryLock(a) {
        boolean result = flag.compareAndSet(false.true);
        if (result) {
            threadLocal.set(true);
        }
        return result;
    }

    /** * release lock */
    public boolean unLock(a) {
        if (threadLocal.get()) {
            threadLocal.set(false);
            return flag.compareAndSet(true.false);
        }
        return false; }}Copy the code

1. First we use AtomicBoolean to define flag bits

2. Create a tryLock method that will attempt to acquire the lock, due to AtomicBoolean’s atomic nature, so that only one thread can modify it successfully

3. Create the unLock method to release the lock and reset the flag bit

4. A ThreadLocal flag is used to initialize a thread’s flag, so that a thread that has not captured the lock changes its flag when it is unLock.

Here we have a simple version of Lock, so let’s test it!

The test code is as follows:

@Slf4j
public class BooleanLockTest {

    public static void main(String[] args) {

        AddThread addThread = new AddThread();
        IntStream.range(0.10).forEach(
                value -> new Thread(addThread).start()
        );
    }

    static class AddThread implements Runnable {
        // Initialize the lock
        private final BooleanLock booleanLock = new BooleanLock();
        // Initializes the I value
        private int i = 0;

        @Override
        public void run(a) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (true) {
                try {
                    // Try to get the lock
                    if (booleanLock.tryLock()) {
                        // Increment operation
                        i++;
                        log.info("Current thread :{}, I :{}", Thread.currentThread().getName(), i);
                        TimeUnit.MILLISECONDS.sleep(current().nextInt(100));
                    } else {
                        TimeUnit.MILLISECONDS.sleep(current().nextInt(100)); }}catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    / / releases the lock
                    if (booleanLock.unLock()) {
                        log.info("Current thread: {} release lock", Thread.currentThread().getName());
                    }
                }
            }
        }
    }
}
Copy the code

The test results are as follows:

... Omit [Thread -5] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -5I value is:16
[Thread-5] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -5Releases the lock [Thread -5] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -5I value is:17
[Thread-5] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -5Releases the lock [Thread -6] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -6I value is:18
[Thread-6] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -6Releases the lock [Thread -6] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -6I value is:19
[Thread-6] the INFO com. Xiaozhi. Atomic. Boo. BooleanLockTest - the current Thread: Thread -6Releases the lock... omitCopy the code

A lot of logging is omitted here, and the result is thread-safe, with only one thread performing the core operation.

Special note: When a lock is not acquired, finally is executed (this is why ThreadLocal is used to store data, preventing the thread from changing the flag directly), and there is no wait state waiting for CPU scheduling. A while loop is then used for unlimited lock preemption.

Here is mainly the use of AtomicBoolean atomic characteristics, to achieve a simple version of the display lock, compared with synchronized, BooleanLock to achieve the effect is that when the thread fails to obtain the lock, it will immediately return the failure, then will not block the solution.

So that’s it for AtomicBoolean; AtomicInteger, AtomicLong, AtomicBoolean are basically operations on Java base types. How do we guarantee atomic operations on our own Java classes?

See the next breakdown: AtomicRefrence, AtomicStampedRefrence

We’ll see!

Public Portal — AtomicBoolean for Concurrent Programming

The code cloud code link is as follows:

Gitee.com/songyanzhi/…

Thanks for reading, and wish you all a happy and healthy work!