java高并发中如何进行线程封闭

发布时间:2021-10-19 16:17:48 作者:柒染
来源:亿速云 阅读:126

这篇文章给大家介绍java高并发中如何进行线程封闭,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

很多时候都想躲避并发,避免并发除了设计成不可变对象其实还有一个简单的方法就是线程封闭。

什么是线程封闭?

其实就是把对象封装到一个线程里,只有这一个线程能看到这个对象。那么这个对象就算不是线程安全的,也不会出现线程安全方面的问题了,因为他只能在一个线程里面进行访问。那么如何实现线程封闭呢?

如何实现线程封闭?

 ThreadLocal

正常来讲我们每一个请求对服务器来讲都是一个线程在运行,我们希望线程间隔离,一个线程在被后端服务器实际处理的时候,可以通过Filter过滤器取出当前的用户,然后将数据存放在ThreadLocal中,当线程被接口的service以及其他相关类进行处理的时候很可能需要在取出当前用户,这时就可以随时随地从ThreadLocal中直接拿到之前存储的值这样用起来就很方便了。如果我们不这样做,会有什么麻烦呢?因为我们的登录用户通常是从request中取出来的,因此需要带上request或者从request中取出来的用户信息,从controller层开始不停的往下传,甚至会传到一些util类中,这样会使得代码看起来很臃肿。当使用ThreadLocal和Filter,就可以很方便的在接口处理之前,前取出相关的信息,在接口实际处理的时候,什么时候需要什么时候再把信息取出来,这样代码在设计的时候就容易多了,不至于把request从controller一直传递下去。

具体使用实例如下:

新建一个类:

public class RequestHolder {
    //因为当前没有登录用户,我们用线程id来充当
    private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();

    /**
     * 请求进入到后端服务器,但是还没有实际处理的时候调用add,可以使用Filter
     * @param id
     */
    public static void add(Long id) {
        //虽然只传入id,但是threadLocal会取出当前线程id放到map中的key,value是传入的值
        requestHolder.set(id);
    }

    public static Long getId() {
        return requestHolder.get();
    }

    /**
     * 如果不做remove的话,会造成内存泄漏,数据永远不会释放掉
     * 需要在接口真正处理完成之后进行调用,可以使用interceptor
     */
    public static void remove() {
        requestHolder.remove();
    }
}

这个类就用来存放ThreadLocal。

新建一个Filter:

@Slf4j
public class HttpFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//        httpServletRequest.getSession().getAttribute("user");
        log.info("do filter , {}, {}", Thread.currentThread().getId(), ((HttpServletRequest) request).getServletPath());
        RequestHolder.add(Thread.currentThread().getId());
        // 如果这个Filter不想拦截住这个请求,只想做单独的数据处理时,要调用chain.doFilter,使得拦截器处理完
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

新建一个Interceptor:

@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        RequestHolder.remove();
        log.info("afterCompletion");
        return ;
    }
}

配置filter和interceptor:

@Configuration
public class Config implements WebMvcConfigurer {

    @Bean
    public FilterRegistrationBean<HttpFilter> httpFilter(){
        FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        // 设置filter
        filterRegistrationBean.setFilter(new HttpFilter());
        // 拦截规则
        filterRegistrationBean.addUrlPatterns("/threadLocal/*");
        return filterRegistrationBean;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
    }
}

新建一个controller进行测试:

@RestController
@RequestMapping("threadLocal")
public class ThreadLocalController {

    @GetMapping("/test")
    public Long test() {
        return RequestHolder.getId();
    }

}

在浏览器中输入localhost:8080/threadLocal/test可以输出线程的id,与后台的输出id一致。

关于java高并发中如何进行线程封闭就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. Java 高并发 回顾线程--多线程基础详细介绍
  2. java高并发中进程和线程是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:如何理解Yarn调度器Scheduler

下一篇:如何根据入参 p1、p2、p3 等的不同组合进行策略定位

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》