线程安全的基本概念
2020-10-16 本文已影响0人
Spicy_Chicken
原子性
如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行,这种特性就叫原子性。
我们通常将这些不可分割的操作称为原子操作。
Java编程规范规定,long、double的赋值和引用操作并不是原子的。因为对于非volatile的long和double变量,JVM允许将64位的读操作或写操作分解成两个32位的操作。
可见性
在没有同步的情况下,编译器、处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得到正确的结论。
加synchronized可同时保证可见性和原子性,而volatile只能保证可见性
volatile boolean asleep;
...
while(!asleep)
doSomething();
调试小提示
对于服务器应用程序,无论是在开发还是测试阶段,当启动JVM时一定都要指定-server命令行选项。server模式的JVM将比client模式的JVM进行更多的优化,例如将循环中未被修改的变量提升到循环外部,因此在开发环境中能正确运行的代码,可能会在部署环境(server模式)中运行失败。例如将volatile去掉的话,server模式可能导致一个无限循环。
发布与逸出
特例:this引用在在构造函数中逸出。参考P33-P34
只有当构造函数返回时,this引用才应该从线程中逸出。构造函数可以将this引用保存到某个地方,只要其他线程不会在构造函数完成之前使用它。
线程封闭
仅在单线程内访问数据,不需要同步。
1.在Swing中大量使用了线程封闭技术,大多数GUI框架都是单线程的(为了线程安全,避免死锁)。
2.JDBC的Connection对象,JDBC规范并不要求Connection对象必须是线程安全的。
栈封闭
维持线程封闭性,使用ThreadLocal类。