多线程与高并发

  1. Volatile

Volatiles是java虚拟机提供的轻量级的同步机制

三大特性:保证可见性,不保证原子性,禁止指令重排

多线程与高并发

  1. CAS

CAS(CompareAndSet) 比较并交换算法,保证数据原子性

UnSafe类是其一个实现的类

多线程与高并发

缺点:循环时间长,开销大。只能保证一个共享变量的原子操作。

AtomicInteger是一个支持原子操作的Integer类,它提供了原子自增方法、原子自减方法以及原子赋值方法等。其底层是通过volatile和CAS实现的,其中volatile保证了内存可见性,CAS算法保证了原子性。

  1. ABA

问题描述:某时刻从内存中取出数据比较并交换,这个时间差会导致数据变化,尽管线程A的CAS操作成功,但是不代表这个过程没有问题

解决方法:原子引用+新增一种机制,修改版本号

atomicReference  ->  automicStampedReference

  1. 不安全集合类

故障现象:java.util.ConcurrentModificationException  并发修改异常

导致原因:并发争抢修改导致

ArrayList解决方案:

    1. 使用线程安全的集合类vector  
    2. 包装成安全的集合类Collections.synchronizedList(new ArrayList<>())  
    3. new CopyOnWriteArrayList<>() 读写分离,源码使用Lock

hashmap解决方案:

  1. 使用线程安全集合类 ConCurrentHashMap
  2. 包装成安全的集合类Collections.synchronizedMap(new HashMap<>()) 

HashSet底层就是HashMap,只是value是一个常量

  1. 公平锁和非公平锁

公平锁:先来后到,吞吐量大

非公平锁(ReentrantLock默认,Synchronized):允许加塞,有可能造成优先级反转或者饥饿现象

  1. 可重入锁(递归锁)

线程可以进入任何一个它已经拥有的锁同步着的代码块

例子:reentrantLock和synchronize

作用:防止死锁

  1. 自旋锁

尝试获取所得线程不会立即阻塞,而是采用循环的方式去获取锁

例子:Unsafe.getAndAddInt

优缺点:优点减少线程上下文切换的消耗,缺点循环会消耗CPU

  1. 独占锁(写锁)/共享锁(读锁)/互斥锁

独占锁:一次只能被一个线程所持有的(reentrantLock和synchronize)

共享锁:可被多个线程锁所持有(reentrantReadWriteLock读操作)

读读  不互斥

读写  互斥

谢谢  互斥

  1. CountDownLatch/ CyclicBarrier/ Semaphore

CountDownLatch:其他操作完成后,再执行当前操作,做减法

CyclicBarrier:先到等待,集齐执行操作,做加法

Semaphore:多个共享资源互斥使用,并发线程数控制

  1. 阻塞队列

阻塞队列为空,取元素被阻塞

阻塞队列为慢,加数据被阻塞

好处:不需要关注什么时候阻塞线程,什么时候唤醒线程,阻塞队列完成

接口:BlockingQueue,和List平级

实现类:

多线程与高并发

多线程与高并发

  1. 生产消费者模型

多线程判断使用while,不能使用if

  1. Synchronize和Lock区别
  1. 原始构成:synchronize是关键字术语jvm层面,lock是具体类是api层面
  2. 使用方法:synchronize不需要手动释放,reentrantlock需要手动释放
  3. 等待是否可中断:synchronize不可中断,reentrantlock可以中断
  4. 加锁是否公平:synchronize非公平锁,reentrantlock默认非公平,可以公平
  5. 绑定多个条件condition:synchronize没有,reentrantlock可以分组唤醒,可以精确唤醒
  1. 线程池

线程池的特点和优点

多线程与高并发

三个常见线程池的使用(底层是ThreadPoolExecutor)

实际应用中都不使用,并发访问量巨大时会出现oom,因此需要手写线程池

多线程与高并发

线程池的七个参数

多线程与高并发

线程池原理

多线程与高并发

 

多线程与高并发

  1. 死锁

两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象

多线程与高并发

查看死锁:

  1. jps –l   定位进程号
  2. jstack 9636   找到死锁查看