!改文章的图片来自java高并发程序设计这本书
并发和并行
- 并发: 主要是指多个任务交替执行。而且这个情况可能出现串行的
- 并行:一般是多个任务同时执行。
死锁、饥饿、活锁的概念
- 死锁一般是指几个线程占用所有 的资源 不释放资源。那么其他线程就不能获得该资源。那么这种情况就会一直持续下去
- 饥饿 是指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行下去。这其中还牵扯到优先级高的线程和优先级低的线程。在争夺资源的时候可能优先级低的线程一直抢不到资源导致处于饥饿的状态。但是饥饿相比死锁的那种情况还是好点,至少在未来的一段时间还能解决的。
- 活锁 就相当于大家都在谦让资源 主动把资源让给别人 。导致一个线程不能拿到所有的资源,不能正常执行下去。
并发级别
- 包含这几种情况,阻塞、无饥饿、无障碍、无锁、无等待。
阻塞
- 当线程处于阻塞的时候,该线程就相当于暂停状态。知道被分配资源后才可以继续执行。 当我们使用synchronized关键字的时候或者我们使用重入锁的时候会出现阻塞的情况。
无饥饿
- 线程之间是有优先级别的,线程调度 总是会先倾向于满足高优先级别的线程。这样是处于不公平的状态,如果线程调度一直给优先级别较高的线程,那么低级别的线程就会一直等不到资源就会处于饥饿状态。这属于不公平锁状态。饥饿状态还是有可能得到资源的 ,不会陷于死锁状态。
无障碍
- 无障碍是一种最弱的非阻塞调度,什么是最弱的呢。那就是大家不会因为临界问题导致一方线程处于挂起状态,如果遇到共享的数据出现问题,呢么就会自动的进行数据回滚,确保数据的安全。
- 我们上面所说数据进行回滚,如果出现所有线程都进行数据回滚,那么程序就进行不下去,我们在非阻塞调度上必须至少保证一个线程能够完成操作,解决办法 我们可以使用 创建一个标记来实现,如在操作前 读取这个标记,在操作完成后再读取该标记查看该标记是否被更改过。两次都是一致的那么资源没有冲突,如果不一致,与其他线程有冲突,就需要进行进行数据回滚。
无锁
- 无锁的并行都是无障碍的。 没有锁的情况下 所有线程都能尝试对临界区资源进行访问。无锁情况下并发保证必然有一个线程能够在有限步馁完成操作。
- 该操作的一个典型特点是 可能包含了一个无穷循环。循环中线程会不断的尝试修改共享变量,在没有冲突的情况下会修改成功,程序执行完毕,否则会继续尝试修改。这是一个碰运气的情况,总会有一个尝试成功。
无等待
- 无等待在无锁的基础上更进一步,要求所有的线程必须在有限的步内完成,这样就不会造成饥饿的状态。如果对步骤进行限制还可以分为 有界无等待,和线程数无关的无等待集中。区别就是 循环次数不同而已。
- 举例说明无等待的结构就是RCE ,读线程 不需要等待。写数据时先得到数据的副本 就是copy一下,然后修改完成后再在某个时候完成对元数据的修改