Java多线程 Concurrent集合与atomic封装类

1、Concurrent集合

Java标准库java.util.concurrent包提供了基于线程安全的集合。针对标准的Java集合类List、Map、Set、Deque,java.util.concurrent包也提供了对应的并发集合类。

interfacenon-thread-safethread-safe
List ArrayList CopyOnWriteArrayList
Map HashMap ConcurrentHashMap
Set HashSet / TreeSet CopyOnWriteArraySet
Queue ArrayDeque / LinkedList ArrayBlockingQueue / LinkedBlockingQueue
Deque ArrayDeque / LinkedList LinkedBlockingDeque

 

使用并发集合类与使用非线程安全的集合类完全相同。

import java.util.concurrent.ArrayBlockingQueue;

Queue q = new ArrayBlockingQueue(0);

2、BlockingQueue

BlockingQueue即阻塞队列,被阻塞的情况主要有两种:队列满了的时候进行入队列操作、队列空了的时候进行出队列操作。因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空队列进行出队列操作时,它将会被阻塞,除非有另一个线程进行了入队列操作。又阻塞队列的特性可知,阻塞队列是线程安全的。

阻塞队列主要用在生产者/消费者的场景,下面这幅图展示了一个线程生产、一个线程消费的场景:

 负责生产的线程不断的制造新对象并插入到阻塞队列中,直到达到这个队列的上限值。队列达到上限值之后生产线程将会被阻塞,直到消费的线程对这个队列进行消费。同理,负责消费的线程不断的从队列中消费对象,直到这个队列为空,当队列为空时,消费线程将会被阻塞,除非队列中有新的对象被插入。

BlockingQueue的实现类有:

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronousQueue

3、atomic

Java atomic封装类,提供了在多线程环境下,无锁进行原子性操作。Atomic包里内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile和native方法,从而避免了synchronized的高开销,提升执行效率。

CAS:compare and swap,比较和替换技术,将预期值与当前变量的值比较(compare),如果相等则使用新值替换(swap)当前变量,否则不作操作;现代CPU已广泛支持CAS指令,如果不支持,那么JVM将使用自旋锁,与互斥锁一样,两者都需先获取锁才能访问共享资源,但互斥锁会导致线程进入睡眠,而自旋锁会一直循环等待直到获取锁。

import java.util.concurrent.atomic.AtomicInteger;

public class Atomic {
    private static int count = 0;
    private static AtomicInteger aiCount = new AtomicInteger(0);

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++) {
                        count++;
                        aiCount.incrementAndGet();
                    }
                }
            };
            t.start();

        }
        System.out.println(count);
        System.out.println(aiCount);
    }

}
// 19948
// 20000

由于自增或自减操作在多线程环境下是不安全的。上述对count变量和 aiCount变量使用20个线程,分别对其1000次自增操作。会发现count变量结果每次并不一致,基于原子封装的 aiCount 变量多线程下均能得到正确结果。

 

 

参考链接:

1、https://www.liaoxuefeng.com/wiki/1252599548343744/1306581083881506

2、https://blog.csdn.net/suifeng3051/article/details/48807423

3、https://my.oschina.net/u/4381576/blog/3416692

posted @ 2021-11-16 14:51  恩恩先生  阅读(167)  评论(0编辑  收藏  举报