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());
}
}
}

JavaSE---ThreadLocal的更多相关文章

  1. JavaSe:ThreadLocal

    JDK中有一个ThreadLocal类,使用很方便,但是却很容易出现问题.究其原因, 就是对ThreadLocal理解不到位.最近项目中,出现了内存泄漏的问题.其中就有同事在使用ThreadLocal ...

  2. 基础1 JavaSe基础

    JavaSe基础 1. 九种基本数据类型的大小,以及他们的封装类 boolean 无明确指定 Boolean char 16bits Character byte 8bits Byte short 1 ...

  3. 回顾javase点滴

    数据类型 8种基本数据类型和引用类型 数据类型 占用位数 存储方式 最小值 最大值 默认值 byte 8 1+7 -128(-2^7) 127(2^7-1) 0 short 16 1+15 -3276 ...

  4. Java中的ThreadLocal使用

    ThreadLocal用于下面的场景: 1. 不允许多个线程同时访问的资源 2. 单个线程存活过程只使用一个实例 官方定义如下: This class provides thread-local va ...

  5. JavaSE 面试题总结

    一. JavaSE 4 1. 面向对象的特征有哪些方面 4 2. String是最基本的数据类型吗? 4 3. super()与this()的区别? 4 4. JAVA的事件委托机制和垃圾回收机制 4 ...

  6. 抛出这8个问题,检验一下你到底会不会ThreadLocal,来摸个底~

    0.问题 和Synchronized的区别 存储在jvm的哪个区域 真的只是当前线程可见吗 会导致内存泄漏么 为什么用Entry数组而不是Entry对象 你学习的开源框架哪些用到了ThreadLoca ...

  7. 面试官:看你简历说写精通ThreadLocal,这几道题你都会吗?

    问题 和Synchronized的区别 存储在jvm的哪个区域 真的只是当前线程可见吗 会导致内存泄漏么 为什么用Entry数组而不是Entry对象 你学习的开源框架哪些用到了ThreadLocal ...

  8. ThreadLocal不好用?那是你没用对!

    在 Java 中,如果要问哪个类使用简单,但用好最不简单?我想你的脑海中一定会浮现出一次词--"ThreadLocal". ​ 确实如此,ThreadLocal 原本设计是为了解决 ...

  9. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  10. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

随机推荐

  1. UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

    py文件直接在cmd窗口用python命令执行时正常:代码逐句在ipython中也正常:但是, 在wingIDE中运行报错“UnicodeEncodeError: 'ascii' codec can' ...

  2. RDA项目打包

    注意APP的编译搭建: ./aps/Makefile.toolchain //ccoption path的设定 ./aps/rules.mak //统一的编译规则 MAKE -C 1.TOOLS的可执 ...

  3. linux 命令2

    who who am i ssh scott@192.168.1.105 ps aux | grep pts/8 pwd // where are you? Page 205 mkdir -p dir ...

  4. MODBUS ASCII和RTU两种模式的区别、优缺点

    转自:http://blog.sina.com.cn/s/blog_89f286ad0102uzju.html 下表是MODBUS ASCII协议和RTU协议的比较: 协议 开始标记 结束标记 校验 ...

  5. 0001_第一个测试小程序Login

    # -*- coding:utf-8 -*- user = raw_input("Username:") password = raw_input("Password:& ...

  6. Maven查找添加方式

    可以通过以下链接 : https://mvnrepository.com/

  7. 1.5 webshell文件上传漏洞分析溯源(1~4)

    webshell文件上传漏洞分析溯源(第一题) 我们先来看基础页面: 先上传1.php ---->   ,好吧意料之中 上传1.png  ---->   我们查看页面元素 -----> ...

  8. hdu 3037 费马小定理+逆元除法取模+Lucas定理

    组合数学推推推最后,推得要求C(n+m,m)%p 其中n,m小于10^9,p小于1^5 用Lucas定理求(Lucas定理求nm较大时的组合数) 因为p数据较小可以直接阶乘打表求逆元 求逆元时,由费马 ...

  9. Halcon - 图像随 HWindowControl 控件缩放的同时,保持图像的长宽比例不变

    背景 通常情况下,图像是填充满 HWindowControl 控件,并随其缩放的.此时只需要将 set_part 的参数设置成图像的大小即可. 不过,有时候,在一些测量任务中,我们对原始图像的长宽比敏 ...

  10. spring-eureka 源码解读----作为集群的eureka怎么样实现不做二次传播

    在平时工作中,eureka作为一个集群时候,我们会配置多个peer ,假设当前有服务器eureka-A,eureka-B,eureka-C. 如果Eureka A的peer指向了B, B的peer指向 ...