1、Java为线程安全提供了工具类,如ThreadLocal等;

2、ThreadLocal类是一个   线程局部变量  ,通过将  ”数据“  放在ThreadLocal中,即可在每条线程中创建一个   ”该数据的拷贝“,从而避免并发访问的线程安全问题;

3、ThreadLocal不能代替同步机制,两者面向的领域不同:

  同步机制:为了同步  多个线程对相同资源的并发访问;

  ThreadLocal:隔离多个线程的资源共享,从根本上避免了多个线程对相同资源的共享冲突;

4、案例:

  使用Filter+ThreadLocal实现在Controller、Service中直接使用某个线程安全对象

  a,web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1" metadata-complete="false">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring.xml
</param-value>
</context-param> <listener>
<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!--MyFilter测试-->
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.exiuge.filtertest.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 -->
<!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter"/> -->
<!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 -->
<!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由servlet container管理 -->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!--阿里Druid内置提供了一个StatViewServlet用于展示Druid的统计信息-->
<!--http://server:port/appname/druid/index.html-->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping> </web-app>

   b,MyFilter

package com.exiuge.filtertest.filter;

import com.exiuge.filtertest.entity.User;
import com.exiuge.filtertest.entity.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import java.io.IOException; public class MyFilter implements Filter { private static final Logger LOGGER= LoggerFactory.getLogger(MyFilter.class); @Override
public void init(FilterConfig filterConfig) throws ServletException {
LOGGER.debug("myFilter init...");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
User user=new User("jack",18,"man");
UserContext.set(user);
filterChain.doFilter(servletRequest,servletResponse);
UserContext.remove();
} @Override
public void destroy() { }
}

  c,User

package com.exiuge.filtertest.entity;

import java.io.Serializable;

public class User implements Serializable {

    private String name;
private int age;
private String sex; public User(){ } public User(String name,int age,String sex){
this.name=name;
this.age=age;
this.sex=sex;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return this.name+this.age+this.sex;
}
}

  d,UserContext

package com.exiuge.filtertest.entity;

public class UserContext{

    private static final ThreadLocal<User> LOCAL_USER=new ThreadLocal<User>();

    public static User get() {
return LOCAL_USER.get();
} public static void set(User user){
LOCAL_USER.set(user);
} public static void remove(){
LOCAL_USER.remove();
}
}

  e,MyController

package com.exiuge.filtertest.controller;

import com.exiuge.filtertest.entity.User;
import com.exiuge.filtertest.entity.UserContext;
import com.exiuge.filtertest.service.MyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Objects; @Controller
@RequestMapping(value = "/myFilter")
public class MyController { private static final Logger LOGGER= LoggerFactory.getLogger(MyController.class); @Autowired
private MyService myService; @RequestMapping(value = "/test")
public String test(){
User user= UserContext.get();
if (Objects.nonNull(user)){
LOGGER.debug("controller:"+user.toString());
myService.test();
}
return "MyFilter Test...";
}
}

  f,MyService

package com.exiuge.filtertest.service;

import com.exiuge.filtertest.entity.User;
import com.exiuge.filtertest.entity.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.Objects; @Service
public class MyService { private static final Logger LOGGER= LoggerFactory.getLogger(MyService.class); public void test(){
User user = UserContext.get();
if (Objects.nonNull(user)){
LOGGER.debug("service:"+user.toString());
}
}
}

最新文章

  1. 你所不知道的linq
  2. [示例] Firemonkey OnTouch 多点触控应用
  3. 100多个基础常用JS函数和语法集合大全
  4. SQL行转列+动态拼接SQL
  5. 关闭ctrl+shift+d截图
  6. Extjs 窗体居中,双重窗体弹出时清除父窗体的鼠标事件
  7. SQLServer批量创建有规则的数据
  8. Devexpress TreeList控件绑定显示父子节点对像
  9. codeforces A. The Wall 解题报告
  10. C++primer 练习11.33:实现你自己版本的单词转换程序
  11. hdu4432 Sum of divisors(数论)
  12. npm 常用命令
  13. 提交服务器 post get
  14. Android网络编程http派/申请服务
  15. Unable to start activity异常的解决方案
  16. 卷积神经网络(CNN)反向传播算法
  17. Netty 4源码解析:请求处理
  18. 刷题upupup【Java中HashMap、HashSet用法总结】
  19. 运行pytorch代码遇到的error解决办法
  20. Beta阶段冲刺集合贴

热门文章

  1. C# winform控件之PictureBox详解
  2. hadoop源码剖析--hdfs安全模式
  3. Unity-2017.2官方实例教程Roll-a-ball(一)
  4. POJ2763 Housewife Wind(树剖+线段树)
  5. poj 2689Prime Distance(区间素数)埃氏筛法
  6. 洛谷 P4512 [模板] 多项式除法
  7. C# Linq 取得两个列表的交集
  8. Jsp介绍(1)
  9. java代码优化(1)---
  10. linux cpu内存利用率获取