为了弄明白什么是线程安全? 可以反向思考
非线程安全会引起什么后果,以及什么是导致非线程安全的因素?
通俗来说,非线程安全就是多个线程并发访问处理,可能导致无法正确处理或者得到正确一致的结果,反过来说,线程安全就是在多线程并发环境下,能始终如一保持结果的正确一致性状态。
举个例子,A, B两个互相冲突的操作,如果在线程安全下执行,最终执行效果应能等价于(A, B)或者(B,A)串行化执行效果。
计算机科学家为了更好地描述非线程安全现象,提出了竞争条件概念。
竞争条件的定义如下(摘自百度百科):
竞争条件指多个线程或者进程在读写一个共享数据时结果依赖于它们执行的相对时间的情形。
竞争条件发生在当多个进程或者线程在读写数据时,其最终的的结果依赖于多个进程的指令执行顺序。
例如:考虑下面的例子
假设两个进程P1和P2共享了变量a。在某一执行时刻,P1更新a为1,在另一时刻,P2更新a为2。
因此两个任务竞争地写变量a。在这个例子中,竞争的“失败者”(最后更新的进程)决定了变量a的最终值。
多个进程并发访问和操作同一数据且执行结果与访问的特定顺序有关,称为竞争条件。
一旦存在竞争条件,共享可变状态变量的变化就无法得到保证,这会导致依赖于该状态变量做决策的后续代码,运行出错
常见竞争条件:检查再运行
为了让代码是线程安全的,我们有两种选择:
1. 根源上消除竞争条件(比如无状态对象,不可变对象,线程局部变量)
2. 事实上避免竞争条件(同步)
由于能够引起竞争条件都是那些针对共享可变的状态变量访问操作,为了在多线程环境下,正确处理避免竞争条件,确保状态一致性,某种意义上,编写线程安全的代码,本质上就是管理对状态的访问,而且通常都是共享,可变的状态。
从上面我们可知 ,在没有正确同步的情况下,如果多个线程访问了同一个变量,你的程序就存在隐患,有3种方法修复它:
1. 不要跨线程共享变量
2. 使状态变量为不可变的
3. 在任何访问状态变量的时候使用同步
对于非线程安全代码,与其在后期修复它(难以维护,甚至失控),不如在一开始就将一个类设计成是线程安全的,这显然来得更容易,那么什么是线程安全类?
当多个线程访问一个类时
1.如果不用考虑这些线程在运行时环境下的调度和交替执行
2.并且不需要额外的同步及在调用方代码不必做其他的协调
3. 这个类的行为仍然是正确的,那么称这个类是线程安全的。
其实线程安全类就是在自身内部同步内部状态变量的访问操作,保护状态一致性。