zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    兼容性处理
    H5 IOS 虚拟键盘不回落的问题
    git 的版本控制
    vue-devtools工具的安装
    linux下安装mysql
    Python安装pip3常见问题
    linux下安装python3
    接口_注册接口
    接口_简单get接口_第一个接口
    Python学习笔记_Redis
  • 原文地址:https://www.cnblogs.com/engeng/p/15561190.html
Copyright © 2011-2022 走看看