在编译器未优化的情况下顺序如下:1.new operator分配适当的内存;2.在分配的内存上构造Singleton对象;3.内存地址赋值给_instance
线程安全是个非常棘手的问题。即使你合理的使用了锁(lock),依然可能不会产生预期的效果。
让我们来看看貌似合理的代码
代码如下:
X=0;
Thread 1 Thread2
lock(); lock();
x++; x++;
unlock(); unlock();
Thread 1 Thread2
lock(); lock();
x++; x++;
unlock(); unlock();
你会认为执行完这两个线程之后,X的一定值等于2?没错,因为lock()和unlock()的保护,x++的执行并不会被打断。(为什么++操作会被多线程给扰乱呢?原因就在于++操作在被编译成汇编之后对应到了多条汇编代码。)但是,编译器却可能因为自作聪明的优化,把x放到register里面(因为寄存器速度快嘛),也就是说当
来源gao!%daima.com搞$代*!码网
Thread1执行完x++之后,被Thread2打断,但是1这个值只保存到了寄存器x里,没有写入内存中的x变量里。随后Thread2执行完成后,内存中x的值等于1,此时,Thread1再执行完,内存中的x又被写入为1.
原来都是编译器倒得鬼!
再看一个例子
代码如下:
x=y=0;
Thread1 Thread2
y=1; x=1;
r1=x; r2=y;
Thread1 Thread2
y=1; x=1;
r1=x; r2=y;
当你拍胸脯向崇拜你的MM保证说:r1或者r2至少有一个为1的时候,可惜编译器又再一次的站到了你的对立面。
原因是早在十几年前还是几十年前,编译器就有了这么一种优化机制,为了提高效率而交换指令的序列。所以上面的代码到了可能变成了这样:
代码如下:
x=y=0;
Thread1 Thread2
r1=x; r2=y;
y=1; x=1;
Thread1 Thread2
r1=x; r2=y;
y=1; x=1;
以上就是深入理解线程安全与Singleton的详细内容,更多请关注gaodaima搞代码网其它相关文章!