private void testDemo(){
this.testRun(beanName,List)
}
private void testRun(bean beanName,List beanName){
.......业务处理
}
定义一个接口,入参的bean实现这个接口,然后参数值是这个接口
可以使用 泛型
public <T> void testRun(T t) {
}
大部分时候我们并没有在项目中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候是存在资源竞争的。
常见的有两种解决办法:
在 bean 中尽量避免定义可变的成员变量。
在类中定义一个 ThreadLocal
成员变量,将需要的可变成员变量保存在 ThreadLocal
中(推荐的一种方式)。
不过,大部分 bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, bean 是线程安全的。
例如我们可以用方法2来检测登录状态,显示登录信息,你可能有疑惑为啥不用session来存储User信息呢?因为服务器是要同时处理多个浏览器的请求的所有服务器会对不同的浏览器创建不同的线程,假如每个线程也就是浏览器都使用同一个bean那么就会产生问题。所以我门应该为一个线程创建一个bean
/**
* 用于替换session
*/
@Component
public class HostHolder {
private ThreadLocal<User> users = new ThreadLocal<>();
public void setUser(User user) {
users.set(user);
}
public User getUser(){
return users.get();
}
public void clear() {
users.remove();
}
}
我们将User对象封装到ThreadLocal中,ThreadLocal为我们提供set和get方法可以将bean放入ThreadLocal和取出,我们来看一下源码
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
其实很好理解,set方法就是先获取当前线程然后以以当前线程为key,要保存的bean为value存储到一个map当中。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
get方法就是以当前线程为key从map中取数据