servlet是单例的,tomcat中会有多个线程去共享servlet。
HashMap是线程不安全的
String是不可变的类,是线程安全的
final String 是线程安全的
Date是线程不安全的
final Date D2 是线程不安全的
说明:添加final关键字不影响变量的线程安全,只是说该变量不能再修改。如果是引用对象,引用不能再修改,但是对象里面的属性还是可以被修改的。所以,final String s2是线程安全的;final Date D2是线程不安全的。
servlet只有一份,那么UserService对象实例也只有一份,所以tomcat中的多个线程会共享这一个实例,会存在线程安全问题。另外count又是成员变量共享资源。
spring中默认的bean对象都是单例的,这里start又是成员变量,多个线程共享start变量,方法中对成员变量进行赋值和修改。所以会有线程安全问题。
解决办法:采用环绕通知,而非前置通知和后置通知,将成员变量做成局部变量,避免线程安全问题。
说明:
dao类里面没有成员变量,只有局部变量,比如connection对象,每个线程都有属于自己的connection对象,所以是线程安全的。
service类里面有成员变量,就是dao,但是dao是private的并且给了固定的值==相当于没有被改变。所以也是线程安全的。
说明:connection对象做成了成员变量,这就有线程安全问题了。因为多个线程共享connection对象,如果第一个线程创建了connection对象还没有使用,第二个线程就执行了conn.close方法将connection对象关闭了。所以应该将connection对象做成线程内私有的局部变量。
说明:这种写法,connection对象作为成员变量就不会有线程安全问题,因为userDao对象变成了局部变量了。但是在开发中不推荐这种写法。
说明:SimpleDateFormat对象虽然是局部变量,但是foo方法是不确定的,如果foo方法被子类复写会开启一个新的线程,那就是线程不安全的。SimpleDateFormat本身不是线程安全的