美文网首页
线程安全与线程不安全的一些理解

线程安全与线程不安全的一些理解

作者: 猫尾草 | 来源:发表于2019-11-08 16:13 被阅读0次

    1. 什么是线程安全和线程不安全?

      我们经常说,StringBuffer是线程安全的,StringBuilder是线程不安全的,这里的线程安全与不安全,指的是在代码没有bug的情况下多线程操作同一个StringBuffer不会出现预料之外的状况,而多线程操作同一个StringBuilder就会出现奇奇怪怪不符合预期的结果
      StringBuilder线程不安全的本质,举个简单的例子来讲讲。StringBuilder通过内部数组的扩容来实现可变长。如果线程A和线程B同时操作同一个StringBuilder的扩容,因为扩容不是原子操作,所以线程A和线程B都在原来的StringBuilder上扩容,线程A先完成扩容,保存扩容后大;线程B后完成扩容,保存扩容后大小。线程B的扩容覆盖了线程A的扩容,线程A扩容新增数据可能丢失也可能因为扩容大小不够而报数组越界的异常。这里只是一个简单的例子,StringBuilder的线程不安全因素还有其他的点。

    2. 线程不安全的分类

    线程不安全可以有以下几种情况:

      1. 某些属性不希望多线程共享,例如计算每个线程里对某个方法执行了多少次。而一般的属性都是多线程共享的,所以不安全;
      1. 某些属性希望多线程共享,但是定义了一些对这些属性的操作,而这些操作不是原子性的,多线程操作结果无法保证,所以不安全。

    对应的解决办法:

      1. 每个线程new一个属于自己的对象,多线程不共享对象(如果这样不会有其他问题);
      1. 对共享对象的操作都加上锁,或者其他保证原子性的方法;
          方法1还有一个特殊情况,静态方法和静态变量,即使每个线程使用的都是自己的对象,不共享,他们仍然共享静态变量;如果一个静态方法操作了静态变量,那么也有安全问题,而如果静态方法不操作静态变量,则没有问题。无论是静态方法还是普通方法,他们都是在各个线程自己的栈中,所以方法中的私有属性不会造成线程安全问题。

    3. 一个解决线程安全性的例子

      web项目中通常具有的controller、service、dao也是多线程(在Tomcat线程足够的情况下,每个请求都开一个线程运行,而不是前一个请求执行完后一个请求才能执行)操作的,controller、service、dao通常只有方法,没有属性,而log等属性本事就是多线程共享的,所以controller、service、dao是多线程安全的。
      Web项目中,除非特别需要,否则不建议在controller、service、dao中使用属性,因为Spring管的Bean默认就是单例的,会造成线程安全问题。如果一定要使用,按照实际情况,要么这些属性给多线程共享,需要加锁等保证原子操作,要么将含有属性的controller、service、dao变为多例(参考https://www.jianshu.com/p/54b0711a8ec8)。

    相关文章

      网友评论

          本文标题:线程安全与线程不安全的一些理解

          本文链接:https://www.haomeiwen.com/subject/ltjnbctx.html