首页 > 其他分享 >JUC包常用类原理

JUC包常用类原理

时间:2023-07-11 18:25:08浏览次数:43  
标签:JUC 常用 int ReentrantLock 线程 new 原理 array public

概要

放眼望去,java.util.concurrent包下类大致包括:atomic 原子类、锁、并发集合、线程池、工具类。我们挑重要的了解一下。

Atomic 原子类

Java针对并发编程已经有了各种锁,为什么还需要原子类?原子类一定有些特别的应用场景?

在很多时候,我们需要的仅仅是一个简单的、高效的、线程安全的递增或者递减方案,这个方案一般需要满足以下要求:

1、 简单:操作简单,底层实现简单

2、 高效:占用资源少,操作速度快

3、 安全:在高并发和多线程环境下要保证数据的正确性

对于是需要简单的递增或者递减的需求场景,使用 synchronized 关键字和 lock 固然可以实现,但代码写的会略显冗余,且性能会有影响,此时用原子类更加方便。

Atomic 类的原理

通过 CAS 实现线程安全访问。CAS 可认为是无阻塞的,一个线程的失败或挂起不会引起其它线程也失败或挂起。但并发量很大的话,CPU 会花费大量的时间在试错上面。如果并发量小的情况,这些消耗可以忽略不计。因此 Atomic 类会因为并发度太高而性能变差。

AtomicInteger

在Java中,++ii++操作并不是线程安全的,因为他们不是原子操作。在并发场景下,数值加减操作有线程不安全,而 synchronized 这种锁又大大降低了并发效率。这时候就可以考虑使用AtomicIntegerAtomicInteger,一个提供原子操作的 Integer 的类。

我们先来看看AtomicInteger给我们提供了什么接口:

int getAndIncrement(); // 获取当前值,然后自加,相当于i++
int getAndDecrement(); // 获取当前值,然后自减,相当于i--
int incrementAndGet(); // 自加1后并返回,相当于++i
int decrementAndGet(); // 自减1后并返回,相当于--i
int getAndAdd(int delta); // 获取当前值,并加上预期值
int getAndSet(int newValue); // 获取当前值,并设置新值

AtomicLong

AtomicLong也是在高并发下对单一变量进行 CAS 操作,从而保证其原子性。

LongAdder

LongAdder类继承了Striped64类,LongAdder是一种以空间换时间的解决方案。其内部维护了一个long类型的base变量,和一个cell数组,当线程写base有冲突时,将其写入数组的一个cell中。将base和所有cell中的值求和就得到最终LongAdder的值了。

  1. 在高并发的场景, AtomicAdderAtomicLong更高效。代价是更高的空间消耗。
  2. 在并发度不高的情况下,AtomicAdderAtomicLong性能差不多。

LongAdder可以作为数据库主键生成器。

Atomic 类总结

并发度不高用 AtomicIntegerAtomicLong,并发度高用LongAdder

AQS

AbstractQueuedSynchronizer(AQS)提供了一套可用于实现锁同步机制的框架。AQS通过一个FIFO队列维护线程同步状态,实现类只需要继承该类,并重写指定方法即可实现一套线程同步机制。AQS根据资源互斥级别提供了独占和共享两种资源访问模式;同时其定义Condition结构提供了wait/signal等待唤醒机制。在JUC中,诸如ReentrantLockCountDownLatch等都基于AQS实现。·

ReentrantLock

ReentrantLocksynchronized的作用是相同的,它们的比较:

  1. 它们都是可重入锁。synchronized是Java语言层面提供的语法,不需要考虑异常,且会自动释放锁,而ReentrantLock是Java代码实现的锁,必须先获取锁,然后在finally中正确释放锁。
  2. ReentrantLock可以尝试获取锁,超时还获取不到锁就可以处理别的事情,如tryLock(long timeout, TimeUnit unit);而synchronized不能,只能一直等待。所以,使用ReentrantLock比直接使用synchronized更安全,线程在tryLock()失败的时候不会导致死锁。
  3. 可中断性:synchronized 锁是不可中断的,无法响应中断请求。ReentrantLock支持中断,可以响应中断请求。
  4. 锁的公平性:synchronized关键字是非公平锁,即不保证等待锁的线程获取锁的先后顺序。ReentrantLock可以实现公平锁和非公平锁,默认是非公平锁,但可以通过构造方法来实现公平锁。公平锁:公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁。

ReentrantLock 使用 Condition 完成等待和唤醒线程的功能

synchronized可以配合waitnotify实现线程在条件不满足时等待,条件满足时唤醒,用ReentrantLock我们怎么编写waitnotify的功能呢?

class TaskQueue {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private Queue<String> queue = new LinkedList<>();

    public void addTask(String s) {
        lock.lock();
        try {
            queue.add(s);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public String getTask() {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                condition.await();
            }
            return queue.remove();
        } finally {
            lock.unlock();
        }
    }
}

可见,使用Condition时,引用的Condition对象必须从Lock实例的newCondition()返回,这样才能获得一个绑定了Lock实例的Condition实例。

Condition提供的await()signal()signalAll()原理和synchronized锁对象的wait()notify()notifyAll()是一致的,并且其行为也是一样的:

  • await()会释放当前锁,进入等待状态;
  • signal()会唤醒某个等待线程;
  • signalAll()会唤醒所有等待线程;
  • 唤醒线程从await()返回后需要重新获得锁。

ReadWriteLock

因为synchronizedReentrantLock这两种锁都是独占锁,每次只允许一个线程执行临界区代码,所以它们比较重量级的锁。有些读多写少的场景,只用保证写的时候只有一个线程,而读的时候可以多个线程同时读。这时候读写锁派上用场了。

ReadWriteLock的特点:

  • 只允许一个线程写入(其他线程既不能写入也不能读取);
  • 没有写入时,多个线程允许同时读(提高性能)

ReadWriteLock大大提高了并发读的执行效率。

注意:如果有线程正在读,写线程需要等待读线程释放锁后才能获取写锁,即读的过程中不允许写,这是一种悲观的读锁。

使用举例:

public class Counter {
    private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
    private final Lock rlock = rwlock.readLock();
    private final Lock wlock = rwlock.writeLock();
    private int[] counts = new int[10];

    public void inc(int index) {
        wlock.lock(); // 加写锁
        try {
            counts[index] += 1;
        } finally {
            wlock.unlock(); // 释放写锁
        }
    }

    public int[] get() {
        rlock.lock(); // 加读锁
        try {
            return Arrays.copyOf(counts, counts.length);
        } finally {
            rlock.unlock(); // 释放读锁
        }
    }
}

并发集合

标签:JUC,常用,int,ReentrantLock,线程,new,原理,array,public
From: https://www.cnblogs.com/cloudrich/p/17545590.html

相关文章

  • Spring中最常用的11个扩展点
    1.自定义拦截器springmvc拦截器根spring拦截器相比,它里面能够获取HttpServletRequest和HttpServletResponse等web对象实例。springmvc拦截器的顶层接口是:HandlerInterceptor,包含三个方法:1.2)preHandle目标方法执行前执行1.2)postHandle目标方法执行后执行1.3)afterCompletio......
  • 计算机cpu的多级缓存简单原理
    缓存级别L1高速缓存(最快内存),一般分为两种方式:指令缓存和数据缓存;一般大小在256KB~1MB之间。L2叫L1缓存慢,比L1会更大些,一般大小在256KB~8MB之间。L3最大的高速缓存存储单元,也是最慢的一个。它的范围从4MB到50MB以上。数据会从RAM依次流到L3高速缓存,然后是L2,最后是L1查找时,会......
  • InnoDB自增原理都搞不清楚,还怎么CRUD?
    虽然我们习惯于给主键ID指定AUTO_INCREMENT属性,但是AUTO_INCREMENT也是可以指定到非主键字段的,唯一的约束就是这个字段上面得加索引,有了索引,就可以通过类似SELECTMAX(*ai_col*)的语句快速读到这列数据的最大值。本文要探讨的话题是MySql的InnoDB引擎处理自增数据列的原理MySql5.1......
  • 77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?
    77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?1.指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传......
  • 基于生长的棋盘格角点检测方法--(1)原理介绍
    前言棋盘格中角点检测方法是相机标定中必不可少的步骤之一。Opencv中的函数boolfindChessboardCorners(InputArrayimage,SizepatternSize,OutputArraycorners,intflags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)就可以轻松实现棋盘格角点检测结果。如下图所示......
  • 浅析synchronized锁升级的原理与实现
    背景在多线程编程中,线程同步是一个关键的概念,它确保了多个线程对共享资源的安全访问。Java中的synchronized关键字是一种常用的线程同步机制,它不仅提供了互斥访问的功能,还具备锁升级的特性。本文将深入探讨synchronized的锁升级原理和实现方式。在jdk1.5(包含)版本之前,因为加锁和......
  • 常用Dos命令
    常用Dos命令打开方式windows键+R(打开cmd的推荐方式)盘符切换C:D:查看当前目录下的所有文件dir切换目录cd同级目录进入下一级目录cd..返回上一级目录通过“cd/d地址”可以访问任意地址清理屏幕cls退出终端exit查看电脑ipipconfig打开应用略ping命令ping+......
  • git 常用命令
    克隆远程库gitclonexxx.git查看本地分支gitbranch 拽取远程分支更新git fetch origin查看远程分支gitbranch-r 切换分支gitcheckout[branch]从当前分支创建新分支,并切换到新分支gitcheckout-bdevelop从远程分支创建新分支,并切换到新分支gitcheckout-......
  • ansible常用模块
    ansible核心内容(模块学习)ansible执行命令结果(状态颜色)绿色:命令以用户期望的执行了,但是状态没有发生改变;黄色:命令以用户期望的执行了,并且状态发生了改变;紫色:警告信息,说明ansible提示你有更合适的用法;红色:命令错误,执行失败;蓝色:详细的执行过程;官网文档如果说学ansible......
  • ICT应用解决方案12-WLAN工作原理
    ICT应用解决方案12-WLAN工作原理1WLAN工作流程1.1AP上线AP获取IP地址并发现AC,与AC建立连接,为确保AP能够上线,AC需预先配置如下内容:配置网络互通:配置DHCP服务器,为AP和STA分配IP地址,也可将AC设备配置为DHCP服务器配置AP到DHCP服务器间的网络互通;配置AP到AC之间的网络......