多线程基础

第一章 多线程

进程:一个独立的应用程序

线程:一条执行路径

1.1 线程安全

发生前提:

1 必须要有俩个以上的线程,需要发生同步

2 多个线程想同步,必须要用到一把锁

3 保证只有一个线程在运行

原理:

1 有一个线程已经拿到了锁,其他的线程已经获得了CPU的执行权,一直在排队,等待其他线程释放锁。

2 锁是什么时候释放? 在代码块执行完毕或者抛出异常都会被释放掉

3 锁已经被释放掉,其他线程开始获取锁进去同步中区

4 锁的资源竞争,多个

5 死锁的问题

缺点:效率非常低

同步函数(函数用synchronized修饰)和同步代码块(this)可以保持同步

静态同步函数不使用this锁,当一个方法被static修饰,存放在永久区,当class文件被加载的时候被初始化,使用当前字节码文件

1.2 死锁(多线程)

发生场景:同步中嵌套同步,无法释放,一直处于等待状态,变为死锁

1.3 多线程3大特性

a原子性:线程唯一,保证线程安全问题

b可见性:java内存模型

c有序性:joinwaitnotify(多线程之间的通讯)

1.4 java内存模型(多线程的可见性 JVM)    

  java内存结构(JVM的内存分配)】

决定了线程与另一个线程是否可见

1.主内存  :存放共享的全局变量

2.私有本地内存 :本地线程的私有变量 ,以及主内存中的共享数据副本,最终会更新主内存的数据

1.5 重排序

cpu会对代码执行实现优化,不会对有依赖关系的进行重排序,代码的执行顺序可能会发现变化,但是执行结果不会发生变化。

多线程可能会发现影响。

1.6 Volatile

作用:

1.保证线程之间可见,但是不保证原子性;

2.volatile修饰的变量,主内存被修改之后可以立即通知其他私有本地内存。保证线程之间数据的可见性

3.可使用atomicinteger的原子类保证线程的安全

4.禁止重排序

1.7 AtomicInteger

jdk1.5引入的原子类,解决线程的安全问题

 

第2章 多线程之间的通讯

2.1 

wait() notify()notifyAll()3个方法都是定义在object方法中,都可用来控制线程的状态,最终调用了jvmnative方法,随着jvm运行平台的不同可能有些许的差异

1. wait 方法:交出该对象的使用权,当前线程处于等待状态

2. notify() :通知某个等待该对象控制权的线程可以运行了

3. notifyAll(); 通知所有等待该对象的控制权的线程可以运行了

注:一定要在线程同步中使用,并且是一个锁的资源

2.2 wait() sleep()区别

1.sleep() 是属于Thread类中的,规定了线程的暂停时间,此时间内不参与CPU的争抢,但是它的监控状态一直保持着,当指定的时间到了又会自动恢复到运行状态,此过程中不会释放对象锁。

2.wait() 是属于object类中的方法,当对象调用此方法时,线程会释放此对象锁,进入等待此对象的等待锁定池,而只有针对此对象的notify()方法时,本线程才会进入对象等待锁定池准备

2.3 Join

让出当前线程的执行权,让别的线程执行完毕,

2.4 ThreadLocal

为本地线程提供一个局部变量,不共享,Map

第3章 java并发包并发队列

3.1 VectorArrayList区别

实现原理都是通过数组,,查询速度快,其慢

Vector 线程安全,效率不高 添加方法被synchronized

ArrayList 效率高

3.2 HashTable HashMap 的区别

HashTable 线程安全  添加方法被synchronized

HashMap线程不安全

3.3 Collections.synchronized*(m)

将不安全的集合转换为安全的集合,上锁

3.4 jdk1.5的并发包

1.ConcurrentHashMap 线程安全,采用分段锁机制,效率高

2.CountDownLatchjdk1.5的并发包)  计数器,调用countDown方法减一,当计数器为0时,wait() 方法之后的代码才会执行。

3.CyclicBarrier  计数器,初始化规定了一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数,当线程达到了这个数目时,所有进入等待的的线程都会被唤醒并继续执行。

 

4.Semaphore 一种基于计数器的信号量,设定一个阈值,多个线程竞争获取许可信号,线程结束后释放,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1Semaphore,将其作为一种类似互斥锁的机制,这也叫2元信号量,表示两种互斥状态。它的用法如下:

availablePermits  函数用来获取当前可用的资源数量

wc.acquire(); //申请资源

wc.release(); //释放资源

3.5 并发队列

1. ConcurrentLinkedQueue 无界高性能队列

2. BlockingQueue 有界阻塞队列 (生产者和消费者)

阻塞与非阻塞区别

有等待时间

第4章 线程池  

【合理配置:CPU密集、IO密集】

4.1 作用

1.降低资源消耗 (重复利用线程,减少等待cpu调度时间)

2.提高响应速度 (当任务到达时,任务可以不需要等到线程创建就能立即执行)

3.管理线程 (线程的创建和分配)

4.2 实现原理

使用阻塞队列

4.3 java 管理线程的核心-----ThreadPoolExecutor

参数:

核心池大小(codePoolSize

最大线程池大小(maximumPoolSize

终止时间(keepAliveTime

超时秒数(unit

 

4.4 Executor封装好了4种线程池

newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。核心线程池为0

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。核心线程池为1

4.5 Future模式

使用callback 执行线程,获取线程执行结果,

4.6 线程池配置多少合适? CPU密集、IO密集

CPU密集【进程花费了绝大多数时间在计算上】 :线程数和CPU数相同

IO密集【等待I/O上花费了大多是时间】  :(操作数据库、IO等待、阻塞、休眠)  配置为 2*CPU

4.7 java的锁机制

1.悲观锁,使用场景,查询量小,

每次取数据的时候上锁

Select * from date where id=1 for update【排他锁】

缺点:执行效率低

  1. 乐观锁

就是每次去拿数据的时候认为别人不会去修改,所以不会上锁,加版本控制,

Update date set status=1,version= version +1  where version =1

  1. 分段锁

ConcurrentHashMap 采用分段锁机制,16个锁的数组,提高请求效率

  1. 重入锁

锁传递给下一个方法,重复使用

非重入锁(死锁)

  1. 读写锁 ReentrantReadWriteLock

Java 读写锁的机制:读-读能共存,读-写不能共存,写-写不能共存

  1. CAS无锁【AtomicInteger

原子类底层实现线程安全 :通过CAS无锁机制

CAS的3个参数:V表示要更新的变量,E表示预期值,N表示新值

仅当V值等于E值时,才会将 V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线 程什么都不做。最后,CAS返回当前V的真实值

  1. 自旋锁

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting

8.排它锁

9.分布式锁

第5章 Disruptor框架

注:第3方的多线程框架

5.1 Disruptor设计来解决队列速度慢的问题:

  1. 底层采用CAS无锁机制,不需要频繁的上下文切换,调用时不需要在用户态与内核态之间切换。
  2. 环形数组结构ringbuffer 来取代队列容器
  3. Ringbuffer 主动推送信息到消费者----------观察者模式

怎么知道推给那个消费者?

Disruptor.headleEventWith(new  LongHeadler()); 注册消费者

  1. 为了避免垃圾回收,采用数组而非链表。同时,数组对处理器的缓存机制更加友好。
  2. 元素位置定位
  3. 数组长度2^n,通过位运算,加快定位的速度。下标采取递增的形式。不用担心index溢出的问题。indexlong类型,即使100QPS的处理速度,也需要30万年才能用完。
  4. 每个生产者或者消费者线程,会先申请可以操作的元素在数组中的位置,申请到之后,直接在该位置写入或者读取数据。

 回顾

Threadlocal的作用是

Threadlocal的原理是

Threadlocal 内存泄漏

Volatile synchronized区别是什么

什么是重排序

什么情况下重排序对程序有影响?

怎么保证线程可见性

并发队列的理解

非租塞队列和阻塞队列的区别

有界队列和无界队列的区别

Jdk的并发包

线程池有哪些分类

线程池实现原理 brolkingqueue

线程池配置多少合适?

threadpoolExecutor有哪些参数

你了解哪些锁

乐观锁和悲观锁有哪些区别

哪些原子类

原子类的原理你有过了解么

什么是CAS无锁机制  ---自旋锁

自旋锁和互斥锁区别---

什么是future模式

Callablethread的区别

你了解哪些并发框架

如何检测死锁 jconsole

lock锁底层原理是什么

你有了解AQS

Synchronized 底层实现原理

内存屏障是怎么回事?

 

 

posted @ 2020-04-23 13:32  守稚心  阅读(155)  评论(0)    收藏  举报