学习路线
在学习Java的路程中,最开始学习JavaSe,在Java基础学完后,开始接触JavaWeb,开始接触框架,Spring框架,SpringBoot框架、数据库框架、在学习一下中间件,就可以完成工作中crud的基础操作,去实现功能了。
但如果一直crud,就无法进步,下一步,就应该更近一步的去学习。
设计模式、代码重构、架构设计、技术选型等等,需要不断深入学习。
有时候做的项目可能并不会涉及分布式,可能就是一些业务,但可能在业务上,也有值得去思考、去深入学习的地方。
一个‘毫无技术含量’的单机系统能有什么技术?
下面是一个单机系统可能涉及的技术,客户端请求进Tomcat,之后进入系统业务代码,同时系统接入数据库DB,再接入一些如Redis、MQ这样的中间件。
池化技术
在连数据库的时候,一般会配置一个数据库连接池,在配置连接池后,其实可以思考,为什么要去配置连接池?很简单,其实就是比例连接的频繁创建和销毁的开销,以达到复用的目的。这其实也可以再深入,为什么创建和销毁连接花销很大,其中就可以再去深入了解操作系统内核相关的知识。
同时,还可以引申出其他的池化技术,比如象池,线程池,内存池,理解这些池在项目中的用处。
多线程
多个线程共同执行任务时,如何提升性能?在使用锁时,理解锁优化,锁升级的过程。如何使用路由把不同的请求,仍给不同的线程池。优化,尽量做串行化无锁编程(比如把每个请求放入一个队列里,由线程去处理,一个线程池一个线程专门处理这些并发请求,这样做,比4个线程并行抢锁性能更高)。
异步处理
很多项目中的代码都是同步处理业务请求,但我们也应该考虑什么地方适合去异步处理任务。这个时候,我们可以深入去了解CompleteFuture在项目的运用。
比如,当一个前端http请求进入后端时,并不仅仅是接受请求,然后开始处理任务。但如果某个业务执行很慢,但请求又频繁,这样会导致多个线程阻塞,影响性能。这种时候就可以考虑使用CompleteFuture实现异步处理,通过回调的方法提高系统的响应速度和吞吐量。
ThreadLocal
将资源和线程绑定,实现无锁编程。
举个例子,比如在JavaWeb开发中,往往都会从Session中获取用户信息,这些信息需要在服务层或DAO层进行使用。为了避免在每个服务层或DAO层方法中都需要传递这些信息,我们可以使用ThreadLocal将这些信息保存在当前线程中,这样在整个线程中都可以轻松地访问这些信息,而不需要在方法间来回传递。例如:
public class UserContext {
private static final ThreadLocal<UserInfo> userInfoThreadLocal = new ThreadLocal<>();
public static void setUserInfo(UserInfo userInfo) {
userInfoThreadLocal.set(userInfo);
}
public static UserInfo getUserInfo() {
return userInfoThreadLocal.get();
}
public static void clear() {
userInfoThreadLocal.remove();
}
}
// 在方法中使用
public void doSomething() {
UserInfo userInfo = UserContext.getUserInfo();
// ...
}
在每个请求处理的时候,我们可以在拦截器中设置当前用户信息,例如:
public class UserInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
UserInfo userInfo = getCurrentUserInfo();
UserContext.setUserInfo(userInfo);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContext.clear();
}
private UserInfo getCurrentUserInfo() {
// 从Session中获取用户信息
return new UserInfo();
}
}
在此之后,UserContext中的userInfoThreadLocal将会持有当前用户信息,并且每个线程都是线程安全的
缓存过滤
在销售系统中,可以使用缓存过滤无效购买请求,如何保证缓存和数据库一致性。
业务隔离
不同的线程池处理不同的业务