I. Atomic variables:

1. AtomicInteger: Indicates the type of an atom

Structure:

public AtomicInteger(int initialValue)
public AtomicInteger()
Copy the code

Methods:

Public final int getAndSet(int newValue) public Final int getAndSet(int newValue) Public Final Int getAndDecrement() getAndDecrement() Public Final Int getAndAdd(int delta) Public final int incrementAndGet() public final int incrementAndGet() Public final int addAndGet(int delta) addAndGet(int delta)Copy the code

For example, the incrementAndGet method increments the variable atomically and returns the incremented value. That is, the operation of getting a value, incrementing it by one, setting it, and then generating a new value does not break.

Related principles:

private volatile int value;
Copy the code

Embellished with volatile to ensure memory visibility

Other types:

  • AtomicBoolean: AtomicBoolean type
  • AtomicLong: AtomicLong type
  • AtomicReference: AtomicReference type……

2. AtomicIntegerArray: atomic array type

Structure:

public AtomicIntegerArray(int length) {
    array = new int[length];
}

public AtomicIntegerArray(int[] array) {
    this.array = array.clone();
}

Copy the code

Common methods:

public final boolean compareAndSet(int i, int expect, int update)
public final int getAndIncrement(int i)
public final int getAndAdd(int i, int delta)
Copy the code

2. Concurrent containers

1, CopyOnWriteArrayList

Features:

  • It is thread-safe and can be accessed concurrently by multiple threads
  • Its iterators do not support modification operations
  • It supports some composite operations atomically
private transient volatile Object[] elements;

Copy the code

Memory visibility is guaranteed with volatile modifications

In the element

/** * add if it does not exist and returntrue
 */
public boolean addIfAbsent(E e) {
    Object[] snapshot = getArray();
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false: addIfAbsent(e, snapshot); } private boolean addIfAbsent(E e, Object[] snapshot) {// Synchronized synchronized (lock) {Object[] current = getArray(); int len = current.length;if(snapshot ! = current) { // Optimizefor lost race to another addXXX operation
            int common = Math.min(snapshot.length, len);
            for (int i = 0; i < common; i++)
                if(current[i] ! = snapshot[i] && Objects.equals(e, current[i]))return false;
            if (indexOf(e, current, common, len) >= 0)
                    return false; Object[] newElements = array.copyof (current, len + 1); newElements[len] = e; // Modify the internal array referencesetArray(newElements);
        return true; }}Copy the code

Get elements:

public E get(int index) {
    return get(getArray(), index);
}
private E get(Object[] a, int index) {
    return (E) a[index];
}
Copy the code

Summary: The CopyOnWriteArrayList array is volatile to ensure that memory is visible, while the write operation is synchronized. The performance is lower, and the read operation does not need synchronization. This method is applicable to multi-threaded operations with few write operations and many read operations.

2, ConcurrentHashMap

Features:

  • Thread safety
  • Segmented lock
  • Read without locking

Principle:

  • ConcurrentHashMap uses segmented locking technology. The data is divided into segments based on the hash value, and each segment has a separate lock, and each segment is equivalent to a separate hash table. Whether you save a key-value pair or look up by key, you map to the segment based on the hash value of the key and then operate on the segment’s corresponding hash table.
  • For write operations, locks need to be acquired and cannot be parallel, but for read operations, multiple reads can be parallel and read at the same time.

Block the queue

1. Blocking queue usage scenarios:

  • When there is no data in the queue, all threads on the consumer side are automatically blocked until data is put into the queue.
  • When the queue is filled with data, all threads on the producer side are automatically blocked until they are woken up at an empty point in the queue.

2. Common blocking queues

  • ArrayBlockingQueue: a bounded blocking queue composed of array structures.
  • LinkedBlockingQueue: a bounded blocking queue consisting of a linked list structure.
  • PriorityBlockingQueue: An unbounded blocking queue that supports priority sorting.
  • DelayQueue: An unbounded blocking queue implemented using priority queues.
  • SynchronousQueue: A blocking queue that does not store elements.
  • LinkedTransferQueue: An unbounded blocking queue consisting of a linked list structure.
  • LinkedBlockingDeque: A two-way blocking queue consisting of a linked list structure.

3. Use:

public class BlockTest{

  private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

  public static void main(String[] args) {
    BlockTest test = new BlockTest();
    Product product = test.new Product();
    product.start();
    Consume consume = test.new Consume();
    consume.start();
  }

  class Product extends Thread {
    @Override
    public void run() {
      try {
        queue.put(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  class Consume extends Thread {
    @Override
    public void run() { try { queue.take(); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

4. Principle:

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {

    ......
    final ReentrantLock lock;

    /** Condition for waiting takes */
    private final Condition notEmpty;

    /** Condition forwaiting puts */ private final Condition notFull; Public E take() InterruptedException {final ReentrantLock lock = this.lock; lock.lockInterruptibly(); Try {// the element is empty to waitwhile (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
    private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] ! = null; final Object[] items = this.items; @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length) takeIndex = 0;
        count--;
        if(itrs ! = null) itrs.elementDequeued(); // Wake up other threads notfull.signal ();returnx; Public void put(E E) throws InterruptedException {object.requirenonNULL (E); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); // The number of elements is equal to the length of the array to wait, when another thread wakes up insert element try {while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    
    private void enqueue(E x) {
        final Object[] items = this.items;
        items[putIndex] = x;
        if(++putIndex == items.length) putIndex = 0; count++; // Wake up other threads notempty.signal (); }... }Copy the code

Conclusion: ReentrantLock is used to avoid thread safety problems caused by multiple threads. Switch between consumer and producer threads with await and signal.

Four, synchronizer:

Private static Semaphore Semaphore = new Semaphore(2); private static Semaphore Semaphore = new Semaphore(2); public static void main(String[] args) {for(int i = 0; i < 5; i ++) {
        new Thread(new Runnable() {
            @Override
            public void run() {try {// Acquire license semaphore.acquire(); System.out.println(Thread.currentThread().getName() +""+ new Date()); Thread.sleep(5000l); Semaphore.release (); } catch (InterruptedException e) { System.err.println(Thread.currentThread().getName() +" interrupted"); } } }).start(); }}Copy the code

Limits the number of concurrent access to a resource

2. CountDownLatch

It is similar to a deadbolt. It is closed at first, and all threads wishing to pass through the door have to wait. Then the countdown begins.

public static void main(String[] args) {
    CountDownLatch countDownLatch = new CountDownLatch(5);
    for(int i = 0; i < 5; i ++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "" + new Date() + " run"); try { Thread.sleep(5000l); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }).start(); } try {//await() checks if the count is 0, if greater than 0, wait countdownlatch.await (); } catch (InterruptedException e) { e.printStackTrace(); }}Copy the code

3. CyclicBarrier

CyclicBarrier blocks the calling thread until the condition is met and the blocking thread is opened at the same time.

public static void main(String[] args) {
    Random random = new Random();
    CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
    for(int i = 0; i < 5; i ++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                int secs = random.nextInt(5);
                System.out.println(Thread.currentThread().getName() + "" + new Date() + " run, sleep " + secs + " secs"); try { Thread.sleep(secs * 1000); CyclicBarrier. Await (); cyclicBarrier. Await (); cyclicBarrier. Await (); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"" + new Date() + " runs over"); } }).start(); }}Copy the code