1、什么是线程安全
线程安全不是线程的安全,而是堆内存的安全
在堆内存中的数据由于可以被任何线程访问到,在没有限制的情况下存在被意外修改的风险
即堆内存空间在没有保护机制的情况下,对多线程来说是不安全的地方,因为你放进去的数据,可能被别的线程“破坏”
2、实现线程安全的解决方案
位置:定义私有变量,仅本线程可访问 保障线程安全
复制:ThreadLocal,线程本地,每个线程拷贝一份数据到在自己线程下,实现互不干扰
class StudentAssistant { ThreadLocal<String> realName = new ThreadLocal<>(); ThreadLocal<Double> totalScore = new ThreadLocal<>(); String determineDegree() { double score = totalScore.get(); if (score >= 90) { return "A"; } if (score >= 80) { return "B"; } if (score >= 70) { return "C"; } if (score >= 60) { return "D"; } return "E"; } double determineOptionalcourseScore() { double score = totalScore.get(); if (score >= 90) { return 10; } if (score >= 80) { return 20; } if (score >= 70) { return 30; } if (score >= 60) { return 40; } return 60; } }
Final: 只能看不能摸,只能读取,不能修改。其实就是常量或只读变量
class StudentAssistant { final double passScore = 60; }
加锁:悲观锁,即默认所有都可能出现线程安全,加锁,其他线程若修改需取到锁 查锁状态,锁未释放只能等候或处理转而处理其他问题
1 class ClassAssistant { 2 3 double totalScore = 60; 4 final Lock lock = new Lock(); 5 6 void addScore(double score) { 7 lock.obtain(); 8 totalScore += score; 9 lock.release(); 10 } 11 12 void subScore(double score) { 13 lock.obtain(); 14 totalScore -= score; 15 lock.release(); 16 } 17 }
CAS: 乐观锁,即默认都会出现线程安全问题,防止ABA问题,加上 版本号,对比当前数据与线程取到的数据,版本号未变线程数安全数据未修改,否则放弃重来
3、引用大神总结:
前两种属于隔离法,一个是位置隔离,一个是数据隔离。
然后两种是标记法,一个是只读标记,一个是加锁标记。
最后一种是大胆法,先来怼一把试试,若不行从头再来。
参考文档 https://www.cnblogs.com/lixinjie/p/10817860.html