同步:
调用者必须等到方法调用返回后,才能继续后续的行为
异步:
异步就像发送一个消息传递,方法调用就会立即返回,调用者可以继续后续的操作。
异步会在另外一个线程中真实的执行,如果需要返回结果,那么后续完成后会通知调用者。
并发concurrency 和并行 parallelism
并行:
并行是多个任务是真实的同时执行
并发:
并发的话任务是在交替执行,一会执行任务a,一会儿执行任务b.
临界区
临界区用来表示一种公共资源或者是共享数据,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要使用这个资源,只能等待。
阻塞blocking 和非阻塞non-blocking
通常是用来形容多线程之间的相互影响。
比如一个线程占用了临界区资源,那么其他所有需要这个资源的线程必须在这个临界区中进行等待。
等待会导致线程被挂起,这种情况就是阻塞。
如果这个线程一直不愿意释放资源,那么其他所有的阻塞在这个临界区的线程都不能工作。
非阻塞的意思是,它强调没有一个线程可以妨碍其他线程执行。
死锁deadlock 饥饿starvation 活锁livelock
描述的是多线程的活跃性问题。
死锁:
比如四两小车互相占据对方的车道。
饥饿:
某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行。
比如它的线程优先级可能太低,而高优先级的线程不断抢占它需要的资源,导致低优先级的线程无法工作。
活锁:
比如两个相对的人,不断给对方让路,但是就是不小心一直妨碍对方。
主动将资源谦让给他人使用,那么就会出现资源不断在两个线程中跳动,而没有一个线程可以同时拿到所有的资源而正常执行。
并发级别
阻塞:
一个线程是阻塞的,那么其他线程释放资源之前,当前线程无法继续执行。
无饥饿
如果线程是有优先级的,那么线程调度时候总会倾向于满足高优先级的线程。
也就是说对于同一资源的分配,是不公平的。
对于非公平的锁,系统允许高优先级的线程插队,但是会导致饥饿
对于公平的锁,那么满足先来后到原则,线程会乖乖执行。
无障碍
无障碍是最弱的一种非阻塞调度。两个线程如果是无障碍执行,那么他们不会因为临界区的问题导致一方被挂起。
如果大家修改共享数据,那么就对自己所修改的数据进行回滚,确保数据安全。
无锁
无锁的并行都是无障碍的,无锁的并发保证必然有一个线程能够在有限步完成操作离开临界区。
无等待
无等待要求所有的线程必须再有限的步完成。
如果限制了步骤的上限,那么就是对循环次数的限制。
并行的两个定律
Amdahl定律
加速比定律:加速比=优化前系统耗时/优化后系统耗时
主要说明:提高系统速度,增加cpu并不一定起到有效作用。需要修改程序串行行为,提高系统的可并行话的模块比重。
Gustafson定律
如果串行比例很小,并行很大,那么加速就是处理器的个数。
JMM(Java内存模型)
原子性(Atomicity)
指一个操作不可以中断。即使是多个线程一起执行,野哥操作一旦开始,就不会被其他线程干扰。
32位系统中long型数据读写都不是原子性。
可见性(visibility)
可见性是一个线程修改了某个共享变量的值,其他线程是否能够立即知道这个修改。
有序性(Ordering)
指令重排:可以保证串行的语义一致,但是没有义务保证多线程之间的语义也一致。
哪些指令不能重排:happen-before规则
程序顺序原则:一个线程内保证语义的串行性
volatile:volatile变量的写,先发生于读,这保证了volatile变量的可见性
锁规则:解锁必然发生在随后的加锁前
传递性:A先于B,B先于C,那么A先于C
线程的start()先于它的每一个动作。、
线程的所有的操作先于线程终结(thread.join())
线程的终端(interrupt())先于被中断的线程的代码
对象的构造函数执行,结束先于finalize()方法
驻守后台:守护线程 daemon
是一种特殊的线程,比如垃圾回收线程,jit线程。
注意:设置守护线程的时候必须在线程start之前设置。
线程的优先级:
使用1到10表示线程的优先级,数字越大优先级越高。