前言

我们都知道,Spring创建出来的对象,默认单例的,所以,我一直在思考一个问题,为何多个线程访问单例对象并未发生并发问题?好像这个问题有点nt,于是我结合我所学到的知识分析了一下。

  1. 并发问题的原因

    多线程访问共享变量,或操作一个可变状态的变量。共享变量很好理解啊,可变状态变量是什么意思呢?举个栗子:多线程访问一个对象的addOneByA()方法,给对象的变量A数值+1,单线程肯定没问题,多线程是有问题的。我们再来分析下,变量A如何+1

    • 线程拿到A的变量
    • 线程做+1操作
    • 线程吧+1后的变量赋给A

    就这三步,我们假如两个线程,同时拿到A变量的数值,然后做+1操作,最终,赋给A的时候A的数值最终只是+1,而不是+2。

  2. 线程隔离

    这个是书里看到的,【每个线程都有各自的程序计数器、栈、局部变量】等。这个就很重要啊,这个说明,非共享、可变状态的变量,多线程操作是没有任何问题的,因为和隔离的。

  3. 解决并发问题

    • 不在线程之间共享该状态变量。就是多线程不访问可变状态变量了呗。
    • 将状态变量修改为不可变变量。就是可变状态变量,变成不可变状态了呗,理解为不可变得常量。
    • 在共享、可变变量的操作【同步】,这个很重要!!!

问题、原理,解决就上面这些东西,可是并发问题,千变万化,还得具体问题具体分析,优化代码是个无底洞,CV能跑得了!

概念

并发产生各种各样的问题,为什么并发难,因为涉及的情况太多,所以要使用一些专用的名词去声明这种情况。

线程安全

何为线程安全,当多线程访问某个类、调用某个类的方法的时候,这个类始终表现出正确的行为这个就是线程安全,很宽泛的一个概念。并且不需要另加同步代码。换句话说就是,你多线程运行的结果,和单线程运行结果一样的话,就是线程安全的。

有状态和无状态

这个很重要,能判断出对象是否是线程安全还是不安全。

有状态

类存储数据,有变量,这就是有状态,多线程操作有状态的对象,可能会并发问题。

无状态

无存储数据、无变量,只是有一些方法,就是各个bean之间调用,保留任何信息。所以,这里又解决了我很久以前的疑问!以前我认为,所有的静态方法,多线程去访问的时候,都是线程不安全的。通过现在的逻辑去推断,并不是。为什么呢?静态方法,也是看状态,只要静态方法不持有【有状态的对象、或者可变状态变量】,只单单有局部变量,那么他就是安全的!

竞态条件

何为竞态条件?【先检查后执行】!详细来说,我们通过一个结果去做一个操作,B的操作依赖A当时的状态,但是A的状态马上就要改了。举个单例的例子

1
2
3
if(a==null){
a=new A();
}

两个线程同时判断interface==null,那么会同时创建一个对象!这个就是竞态条件,一个结果,依赖了可能马上要消失的结果,肯定会产生很多问题,或者这样说,出不出问题,完全看运气。