JUC及Tools工具类,并发集合

本文详细介绍了Java并发编程中的CAS算法、原子类、Volatile特性以及JUC中的锁机制,包括重入锁和读写锁。讨论了synchronized与Lock的区别,并介绍了LockSupport工具类。此外,还讲解了并发集合如CopyOnWriteArrayList、CopyOnWriteArraySet和ConcurrentHashMap的原理与特性,分析了它们与HashMap的不同之处。
摘要由CSDN通过智能技术生成

1.CAS: 比较和交换算法. 乐观锁(通过算法的形式达到了原子性)

a++:

*       1.从主内存中拷贝变量到线程的工作内存中, 保存主内存中变量的副本
*       2.线程在工作内存中操作变量副本
*       3.将工作内存中的值同步到主内存, 比较副本值和主内存中的值
*           相同: 同步到主内中
*           不相同: 从第一步从新开始(循环)
*       通常CAS配合Volatile使用  	
*   	通过Volatile和CAS实现锁的效果, CAS无锁的操作, 没有死锁的问题
缺点
1. 多线程操作时每次修改值时,可能多次出现内存值和副本值不同的情况,需要循环执行多次

2. 可能出现ABA问题
为了解决ABA问题,一般都会在操作时设置一个int类型版本号(version),每次对内存中变量操作后都让版本号加1。
当需要修改变量时,除了比较副本中值和内存值以外,还需要比较版本号是否相同。JDK中AtomicStampedReference就是这种方式,
提供了全局int属性

1_1原子类

原子性:操作过程中不允许其他线程干扰, 可以理解为数据操作是整体,整体只有成功或失败,不允许出现部分成功部分失败

AtomicInteger:
底层使用的是volatile和cas
incrementAndGet(): 先加1,在获取,类似于++num。

getAndIncrement():先获取,后加1,类似于num++。

addAndGet(int);先在原值上增加指定值,后获取结果。

getAndSet(int):先获取,后设置值。

decrementAndGet():先减1,在获取,类似--num。

getAndDecrement():先获取,在减1,类似num--。

set(int):设置值。

get()返回value值。

2.Volatile:

 是JMM中三大特性之一,在多线程情况下.,可以保证共享数据的可见性,有序性但是不能保证数据操作的原子性(数据操作是整体,整体只有成功或失败,不允许出现部分成功部分失败),多线程情况下volatile修饰的变量线程不安全.
  可见性
*       线程操作副本值后, 立刻同步到主内存中
*       变量被修改, 其他线程能立即知道这个变量的变化,其他线程使用该变量前, 从主内存中拷贝最新的变量
* 实现原理:
* 	多核cpu情况下,为了提高处理速度,cpu不直接对主内存进行操作,而是在cpu和内存之间加入了高速缓存,进行数据操作时,先把数据从主内存拷贝到高速缓存       
* 中,cpu直接操作高速缓存中的数据,,在多处理器情况下,可能会出现高速缓存数据不一致的问题,引入可见性,为了保证缓存数据一致性,加入缓存一致性协议,底层是
* 用总线嗅探机制实现,当变量发生变化时,副本的值和主内存的值不一致,处理器就将副本值设置为无效状态,使用前,再从主内存中拷贝最新的值.
* 下面是对上面的总结:
*           添加了缓存一致性协议, 拷贝 | 同步 变量值时, 都需要经过缓存一致性协议,
*           总线嗅探机制, 变量值发生修改, 副本中的值和主内存中的值不一致, 使用前,
*           将副本值设置为无效状态, 使用时, 拷贝最新的主内存中的变量值
  有序性:
*   java编译器生成字节码文件时,会在指令序列中插入内存屏障(CPU处理器的指令)来禁止CPU处理器重排序
* volatile 尽量少用.否则会导致总线风暴,当某个变量不想被指令重排,保证可见性,可以使用volatile修饰
* 可以用synchronized锁进行代替

在这里插入图片描述

3.JUC中的锁:

JUC中的锁底层实现为AQS:

* 		全名是AbstractQueueSynchronizer,是并发容器下locks包的一个类 
*      AQS: 底层为队列, FIFO(先进先出)
* 			队列是由双向链表实现
*           存储要执行操作资源的线程.
* 	        被请求的资源被占用,其他线程则去队列排队
*           被操作的资源有一个state属性, state>0 上锁了  state=0 没有加锁
*           state需要使用CAS操作
*

4. 重入锁: 一个线程允许多次持有同一把锁

* ReentrantLock: 重入锁   synchronized: 重入锁
*       ReentrantLock: 公平锁  非公平锁
*           公平锁: 新的执行任务的线程在队列中排队
*           非公平锁: 先抢锁抢到了就执行, 没有抢到再去排队
*
* Condition: 本身是一个接口,,通过lock.newCondition()   实例化,  
*       线程等待  唤醒线程
*       condition.await()
*       condition.single()
*       condition.singleAll()

ReentrantReadWriteLock: 读写锁
* 读锁: 共享锁
* 多个线程可以同时持有
* 写锁: 排它锁
* 只能一个线程持有
LockSupport.park() : 暂停线程
* LockSupport.unPark() : 恢复线程
* 释放锁: 必须使用在有所的代码块中
不释放锁:
* 1.可以用在有锁的代码块中
* 2.可以用在没有锁的代码块中

4_1synchronized和lock的区别

  1. 类型不同

​ synchronized是关键字。修饰方法, 修饰代码块

​ Lock是接口

  1. 加锁和解锁机制同步

​ synchronized是自动加锁和解锁,遇到异常自动释放锁,程序员不需要控制。

​ Lock必须由程序员控制加锁和解锁过程,需要注意出现异常不会自动解锁
如果要在抛异常的时候释放锁,在finnally中释放锁

  1. 异常机制

​ synchronized碰到没有处理的异常,会自动解锁,不会出现死锁。

​ Lock碰到异常不会自动解锁,会出现死锁。所以写Lock锁时都是把解锁放入到finally{}中。

  1. Lock功能更强大

​ Lock里面提供了tryLock()/isLocked()方法,进行判断是否上锁成功。synchronized因为是关键字,所以无法判断。

  1. Lock性能更优

​ 如果多线程竞争锁特别激烈时,Lock的性能更优。如果竞争不激烈,性能相差不大。

  1. 线程通信方式不同

​ synchronized 使用wait()和notify()线程通信。
​ Lock使用Condition的await()和signal()通信。

  1. 暂停和恢复方式不同

​ synchronized 使用suspend()和resume()暂停和恢复,这俩方法jdk1.2过时了。

​ Lock使用LockSupport中park()和unpark()暂停和恢复,这俩方法没有过时。

5.Tools:

*      CountDownLatch: 计数器
*          cdl.await(): 计数器的值>0, 线程阻塞
*                        计数器的值=0, 线程继续执行
*          cdl.countDown(): 调用一次计数器的值-1
*

6.并发集合类:

ArrayList: 线程不安全的
* Vector: 线程安全, get add 都有锁
* CopyOnWriteArrayList: 写时复制
* 添加元素时, 拷贝数组, 向新数组中添加
* 读取元素可以在原数组中操作, 可以并发的读

并发集合类:主要是提供线程安全的集合

比如:

​ 1. ArrayList对应的并发类是CopyOnWriteArrayList

​ 2. HashSet对应的并发类是 CopyOnWriteArraySet

​ 3. HashMap对应的并发类是ConcurrentHashMap

CopyOnWriteArrayList
写时复制

​ 通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后往新的容器里添加元素

​ 添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

​ 对于读操作远远多于写操作的应用非常适合,特别在并发情况下,可以提供高性能的并发读取。

​ CopyOnWrite容器只能保证数据的最终一致性,不能保证数据实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

CopyOnWriteArrayList重点源码

public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
   
  //创建不可改变的对象
  final transient Object lock = new Object();
  //volatile修饰的Object类型的数组, 保证了数组的可见性, 有序性
  private transient volatile Object[] array;

  //获取元素, 根据下标获取元素, 支持多线程查询
  public E get(int index) {
   
    return elementAt(getArray(), index);
  }   

  //设置数组
  final void setArray(Object[] a) {
   
    array = a;
  }

  //添加元素, 写时复制
  public boolean add(E e) {
   
    //加锁
    synchronized (lock) {
   
      //获取当前数组
      Object[] es = getArray();
      //获取数组的长度
      int len = es.length;
      //复制旧数组, 长度+1, 创建一个新数组
      es = Arrays.copyOf(es, len + 1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值