mysql怎么保证线程安全_这8种保证线程安全的技术你都知道吗?

并发情况下如何保证数据安全,一直都是开发人员每天都要面对的问题,稍不注意就会出现数据异常,造成不可挽回的结果。笔者根据自己的实际开发经验,总结了下面几种保证数据安全的技术手段:

无状态

不可变

安全的发布

volatile

synchronized

lock

cas

threadlocal

一.无状态

我们都知道只有多个线程访问公共资源的时候,才可能出现数据安全问题,那么如果我们没有公共资源,是不是就没有这个问题呢?

public class NoStatusService {publicvoidadd(String status) {System.out.println("add status:" + status);}publicvoidupdate(String status) {System.out.println("update status:" + status);}}

二.不可变

如果多个线程访问公共资源是不可变的,也不会出现数据的安全性问题。

public classNoChangeService{public static final String DEFAULT_NAME = "abc";publicvoidadd(String status){System.out.println("add status:" + status);}}

三.安全的发布

如果类中有公共资源,但是没有对外开放访问权限,即对外安全发布,也没有线程安全问题

public class SafePublishService {private String name;publicString getName() {return name;}publicvoidadd(String status) {System.out.println("add status:" + status);}}

四.volatile

如果有些公共资源只是一个开关,只要求可见性,不要求原子性,这样可以用volidate关键字定义来解决问题。

public class FlagService {public volatile boolean flag = false;publicvoidchange() {if (flag) {System.out.println("return");return;}flag = true;System.out.println("change");}}

五.synchronized

使用JDK内部提供的同步机制,这也是使用比较多的手段,分为:方法同步 和 代码块同步,我们优先使用代码块同步,因为方法同步的范围更大,更消耗性能。每个对象内部都又一把锁,只有抢答那把锁的线程,才能进入代码块里,代码块执行完之后,会自动释放锁。

public classSyncService{private int age = 1;publicsynchronized voidadd(inti){age = age + i;System.out.println("age:" + age);}publicvoidupdate(inti){synchronized (this) {age = age + i;System.out.println("age:" + age);}}}

六.lock

除了使用synchronized关键字实现同步功能之外,JDK还提供了lock显示锁的方式。它包含:可重入锁、读写锁 等更多更强大的功能,有个小问题就是需要手动释放锁,不过在编码时提供了更多的灵活性。

public class LockService {private ReentrantLock reentrantLock = new ReentrantLock();public int age = 1;publicvoidadd(inti) {try {reentrantLock.lock();age = age + i;System.out.println("age:" + age);} finally {reentrantLock.unlock();}}}

七.cas

JDK除了使用锁的机制解决多线程情况下数据安全问题之外,还提供了cas机制。这种机制是使用CPU中比较和交换指令的原子性,JDK里面是通过Unsafe类实现的。cas需要四个值:旧数据、期望数据、新数据 和 地址,比较旧数据 和 期望的数据如果一样的话,就把旧数据改成新数据,当前线程不断自旋,一直到成功为止。不过可能会出现aba问题,需要使用AtomicStampedReference增加版本号解决。其实,实际工作中很少直接使用Unsafe类的,一般用atomic包下面的类即可。

public classAtomicService{private AtomicInteger atomicInteger = new AtomicInteger();publicintadd(inti){return atomicInteger.getAndAdd(i);}}

八.threadlocal

除了上面几种解决思路之外,JDK还提供了另外一种用空间换时间的新思路:threadlocal。它的核心思想是:共享变量在每个线程都有一个副本,每个线程操作的都是自己的副本,对另外的线程没有影响。特别注意,使用threadlocal时,使用完之后,要记得调用remove方法,不然可能会出现内存泄露问题。

public class ThreadLocalService {private ThreadLocal threadLocal = new ThreadLocal<>();publicvoidadd(inti) {Integer integer = threadLocal.get();threadLocal.set(integer == null ? 0 : integer + i);}}

总结

本文介绍了8种多线程情况下保证数据安全的技术手段,当然实际工作中可能会有其他。技术没有好坏之分,主要是看使用的场景,需要在不同的场景下使用不同的技术。

如果这篇文档对您有所帮助的话,麻烦关注一下我的公众账号:苏三说技术,或者帮忙点赞或转发,坚持原创不易,您的支持是我坚持最大的动力。后面我会分享更多更实用的干货,谢谢大家的支持。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值