线程安全实际上指的是内存的安全。
由于进程中的线程都是共享资源的。每个进程的内存空间都会有一块堆内存,所有的线程都会访问到这个区域,这就导致问题的产生。
例如线程1保存的数据被线程2改动导致线程1继续进行的是出现错误。
局部变量
为每个线程分配属于自己的空间,称为栈内存,是其他线程无法访问的。
常见的有 局部变量 。某个方法被两个线程同时使用时,方法中的局部变量会分别保存在线程的栈内存中,也就是说每个线程会有自己单独的一份数据。互不打扰。
但是这时这个数据被限制在该方法中使用。其他方法不能使用。
ThreadLocal
局部变量不能再别的方法中使用,因此可以使用ThreadLocal类来定义变量,这时候每个线程在运行时都会拷贝一份在自己的栈内存中。
只读变量
,只能用不能改也可以保证内存的安全,一些不需要修改的变量可以用只读变量来定义用final来修饰。
以上三种可以用在比较简单的场景中。
互斥锁
就是先到先用,锁起来,用完之后在释放,给别人用。 用Lock 类。
用法:
lock.obtain()上锁
使用方法体
lock.release() 释放锁
CAS
如果线程较少,锁会比较耗时耗力,在并发很小的情况下,可以使用CAS。
意思就是记录下当前的数据的状态,再次使用时拿出来比较一下,如果不愿意说明被改动了,就放弃重新处理一遍。
如果担心发生ABA事件,数据被改了,然后又被改回来了,就可以在加一个版本号来区分。
总结
前两种就是将数据隔离起来,一个时位置隔离,一个是数据隔离。
之后两个是属于标记法,只读标记和加锁标记。其中加锁属于悲观锁。
最后一个属于乐观锁,只适合并发很少的情况使用。