Created: Aug 6, 2020 8:45 PM
Tags: 临界区, 原子性、可见性、有序性, 同步异步, 并发并行, 死锁、饥饿、活锁
用来形容一次方法调用。
用来表示一种公共资源。可以被多个线程使用。但是每次只能有一个线程使用。线程需要等待其他线程使用完该资源。
用来形容多线程之间的相互影响。
多个线程互相占用对方需要的资源,同时本身不愿意放弃自己的资源,导致死锁
![线程死锁]](https://img-blog.csdnimg.cn/img_convert/d98885594a3ef0970b7af25a57878e1b.png#pic_center)
线程资源的分配不是根据先到先得的,获得资源存在了一定的“运气”,一个线程因为种种原因无法获得所需要的资源,导致无法执行,称为饥饿
多个线程互相谦让,资源始终在两个线程之间跳动,却没有被使用。
指一个操作不可中断。
对于32位的系统,long型的数据读写不是原子性的(long有64位)。
在32位的环境下,并发读写long数据,结果将很神奇。
当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。串行程序不需要考虑可见性。
并行程序中,将可能发生问题
某个线程修改了某一个全局变量,其他线程不一定能立刻知晓改动。
因为线程之间操作不可见导致的指令重排问题
下侧的代码在运行时,看起来没什么问题,
public void T1(){
r2 = A;
B = 1;
}
public void T2(){
r1 = B;
A = 2;
}
重排后
A=2
r2=A=2;
B=1;
r1=B=1;
指令重排不保证多线程之间的有序,只能保证本线程内语义一致。
类似上面的代码,指令重排将可能导致多线程之间操作逻辑错误。
Happen-Before规则主要保证指令重排不会破坏原有的语义结构
Created: Aug 6, 2020 9:40 PM
Tags: 无等待, 无锁, 阻塞, 饥饿
由于临界区的存在,多线程之间并发必须受到控制。
根据控制并发的策略,将并发的级别进行分类,大致分为阻塞、无饥饿、无锁、无等待几种
在其他线程释放资源前,当前线程无法继续执行。
使用synchronized关键字或重入锁。
非公平的锁允许“插队”的情况。公平的锁满足先来后到,饥饿将不会产生,所有线程都有机会执行。
最弱的非阻塞调度。
两个线程进入临界区不会挂起。若监测到数据错误,将对修改进行回滚,确保数据安全。若无竞争发生,这完成工作,走出临界区。
隐含的问题:临界区存在严重的冲突,所有的线程都在回滚操作,没有一个能走出临界区。需要在此时保证有一个能够在有限时间内完成自己的操作。
实现方式之一:“一致性标记”,操作前保存标记,完成后进行检查。一样则正常。
存在的漏洞:该线程在临界区内运行时,第三者获取到了临界区,进行了操作,并将标记恢复,导致不能识别。
无锁的并行都是无障碍的。所有线程都能尝试对临界区访问。但,无锁的并发保证必然有一个线程能够在有限步内完成操作并离开临界区。
典型特点:无限循环,不断尝试修改。
在无锁的基础上进一步扩展。要求所有的线程都必须在有限步内完成,这样不会引起饥饿问题。
典型无等待:RCU(Read-Copy-Update)对数据的读不加控制。写数据时,获取数据副本,进行操作,合适的时机写回。