一、高并发的常用概念
1.1 同步(Synchronous)和异步(Asynchronous)
很明显,同步调用会等待方法的返回,异步调用会瞬间返回,但是异步调用瞬间返回并不代表你的任务就完成了,他会在后台起个线程继续进行任务。
1.2 并发(Concurrency)和并行(Parallelism)
并行则是两个任务同时进行,而并发呢,则是一会做一个任务一会又切换做另一个任务
1.3 临界区
临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用,但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待
1.4 阻塞(Blocking)和非阻塞(Non-Blocking)
阻塞和非阻塞通常形容多线程间的相互影响
1.5 死锁(Deadlock)、饥饿(Starvation)、活锁(LiveLock)
死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
1.5.1 java 多线程死锁
如果出现死锁,可以使用JDK自带的命令行工具
jsp
jstack
饥饿:指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行
活锁:指事物1可以使用资源,但它让其他事物先使用资源;事物2可以使用资源,但它也让其他事物先使用资源,于是两者一直谦让,都无法使用资源
1.6 并发级别
并发级别:阻塞和非阻塞(非阻塞分为无障碍、无锁、无等待)
1.6.1 阻塞
当一个线程进入临界区后,其他线程必须等待
1.6.2 无饥饿
因为线程有优先级别,导致低优先级始终都不能执行到。如果使用队列,FIFO,则能保证被执行
1.6.3 无障碍
无障碍是一种最弱的非阻塞调度
1.6.4 无锁
与无障碍相比,无障碍并不保证有竞争时一定能完成操作,因为如果它发现每次操作都会产生冲突,那它则会不停地尝试。如果临界区内的线程互相干扰,则会导致所有的线程会卡死在临界区,那么系统性能则会有很大的影响。而无锁增加了一个新的条件,保证每次竞争有一个线程可以胜出,则解决了无障碍的问题。至少保证了所有线程都顺利执行下去。
1.6.5 无等待(Wait-Free)
一种典型的无等待结构就是 RCU(Read-Copy-Updat
). 所有的读线程都是无等待的。写数据,先在副本上修改。然后再写回主数据。
1.7 原子性(Atomicity)
原子性是指一个操作不可再分(不能中断)
1.8可见性(Visibility)
可见性是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改值。
Happen-Before规则
JSR-133使用happen-before
的概念来指定两个操作之间的执行顺序。由于这两个操作可以在一个线程之内,也可以是在不同线程之间。因此,JMM可以通过happen-before
关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happen-before
关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)
• volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性
• 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
• 传递性:A先于B,B先于C,那么A必然先于C
• 线程的start()方法先于它的每一个动作
• 线程的所有操作先于线程的终结(Thread.join())
• 线程的中断(interrupt())先于被中断线程的代码
• 对象的构造函数执行结束先于finalize()方法
参考
- 《实战java高并发程序设计》