3 内存模型和线程安全

mac2024-10-27  13

原子性

原子性是指一个操作是不可中断的,即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

有序性

在并发时,程序的执行可能就会出现乱序。一条指令的执行是可以分为很多步骤的,一个内核一个时钟周期可以处理两个不同的步骤。 — 取指 IF — 译码和取寄存器操作数 ID — 执行或者有效地址计算 EX — 存储器访问 MEM — 写回(寄存器) WB     上图中“x”表示当前时钟频率内的的步骤无操作,因为下一步的操作需要上一步的结果做参数,所以需要等待上一步指定步骤的完成。如果要消除此动作,需要把规整的步骤打乱,如下:     此操作为指令重排,可以使流水线更加顺畅。指令重排的前提是不破坏程序结果的执行顺序,d不能比a更早赋值,这只是CPU优化处理性能的一种方式。

可见性

可见性是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。可见性是一个整体性的问题,会出现在各个层面。 编译器优化(每个CPU都有自己的寄存器和高速缓存,如一个线程中某个变量被优化到了一个CPU的寄存器中,另一个线程对这个变量的值存入到另一CPU的高速缓存中,不能保证这两个值一定是一致的。多核CPU之间有一致性的协议,协议很松散,需消耗一定的性能。)硬件优化(如写吸收,批操作)如CPU想把一个数据写到内存中,很慢,就会使用硬件队列来实现,通过批量操作把硬件队列写到内存中,会快一些,硬件队列也会有一些优化,如果CPU对同一个内存地址对此读写,会以最后一次读写为准,前面老的读写不会被写入内存中。 Java虚拟机层面的可见性。 参考:http://hushi55.github.io/2015/01/05/volatile-assembly

Happen-Before

程序顺序原则:一个线程内保证语义的串行性volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性锁规则:解锁(unlock)必然发生在随后的加锁(lock)前传递性:A先于B,B先于C,那么A必然先于C线程的start()方法先于它的每一个动作线程的所有操作先于线程的终结(Thread.join())现成的中断(interrupt())先于被中断线程的代码对象的构造函数执行结束先于finalize()方法

线程安全的概念

指某个函数、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。 public class AccountingSync implements Runnable{ static AccountingSync instance=new AccountingSync(); static int i=0; @Override public void run() { for(int j=0;j<10000000;j++){ synchronized(instance){ //通过阻塞保证线程安全 i++; } } }
最新回复(0)