Java并发知识总结,超详细!(下)

接着来~
原子类
基本类型原子类

使用原子的方式更新基本类型

AtomicInteger:整型原子类
AtomicLong:长整型原子类
AtomicBoolean :布尔型原子类
AtomicInteger 类常用的方法:

public final int get() //获取当前的值public final int getAndSet(int newValue)//获取当前的值,并设置新的值public final int getAndIncrement()//获取当前的值,并自增public final int getAndDecrement() //获取当前的值,并自减public final int getAndAdd(int delta) //获取当前的值,并加上预期的值boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。

AtomicInteger 类主要利用 CAS (compare and swap) 保证原子操作,从而避免加锁的高开销。
数组类型原子类
使用原子的方式更新数组里的某个元素

AtomicIntegerArray:整形数组原子类
AtomicLongArray:长整形数组原子类
AtomicReferenceArray :引用类型数组原子类
AtomicIntegerArray 类常用方法:

public final int get(int i) //获取 index=i 位置元素的值public final int getAndSet(int i, int newValue)//返回 index=i 位置的当前的值,并将其设置为新值:newValuepublic final int getAndIncrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自增public final int getAndDecrement(int i) //获取 index=i 位置元素的值,并让该位置的元素自减public final int getAndAdd(int i, int delta) //获取 index=i 位置元素的值,并加上预期的值boolean compareAndSet(int i, int expect, int update) //如果输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update)public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。

引用类型原子类
AtomicReference:引用类型原子类
AtomicStampedReference:带有版本号的引用类型原子类。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
AtomicMarkableReference :原子更新带有标记的引用类型。该类将 boolean 标记与引用关联起来
AQS
AQS定义了一套多线程访问共享资源的同步器框架,许多并发工具的实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch。

原理
AQS使用一个volatile的int类型的成员变量state来表示同步状态,通过CAS修改同步状态的值。

private volatile int state;//共享变量,使用volatile修饰保证线程可见性
同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态(独占或共享 )构造成为一个节点(Node)并将其加入同步队列并进行自旋,当同步状态释放时,会把首节中的后继节点对应的线程唤醒,使其再次尝试获取同步状态。
在这里插入图片描述
Condition
任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,使用这些方法的前提是已经获取对象的锁,和 synchronized 配合使用。Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式。Condition是依赖Lock对象。

Lock lock = new ReentrantLock();Condition condition = lock.newCondition();public void conditionWait() throws InterruptedException {    lock.lock();    try {            condition.await();    } finally {            lock.unlock();    }}public void conditionSignal() throws InterruptedException {    lock.lock();    try {            condition.signal();    } finally {            lock.unlock();    }}

一般将Condition对象作为成员变量。当调用await()方法后,当前线程会释放锁进入等待队列。其他线程调用Condition对象的signal()方法,唤醒等待队列首节点的线程。
实现原理
每个Condition对象都包含着一个等待队列,如果一个线程成功获取了锁之后调用了Condition.await()方法,那么该线程将会释放同步状态、唤醒同步队列中的后继节点,然后构造成节点加入等待队列。只有当线程再次获取Condition相关联的锁之后,才能从await()方法返回。
在这里插入图片描述
图片来源:Java并发编程的艺术
在Object的监视器模型上,一个对象拥有一个同步队列和等待队列。Lock通过AQS实现,AQS可以有多个Condition,所以Lock拥有一个同步队列和多个等待队列。
在这里插入图片描述
图片来源:Java并发编程的艺术
线程获取了锁之后,调用Condition的signal()方法,会将等待队列的队首节点移到同步队列中,然后该节点的线程会尝试去获取同步状态。成功获取同步状态之后,线程将await()方法返回。
在这里插入图片描述
其他
Daemon Thread

在Java中有两类线程:

User Thread(用户线程)
Daemon Thread(守护线程)
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是垃圾收集。

将线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现。
文章来源:https://www.tuicool.com/articles/7nINbeb
作者:博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值