线程数据共享和安全 -ThreadLocal

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 线程数据共享和安全 -ThreadLocal

线程数据共享和安全 -ThreadLocal-----Java web文件上传下载应该注意什么


ThreadLocal


  1. 1、ThreadLocal 可以实现在同一个线程数据共享, 从而解决多线程数据安全问题。
  2. 2、ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法设置 关联数据。
public void set(T value) {
//获取当前线程
* Thread t = Thread.currentThread();
* //获取当前线程的 ThreadLocal.ThreadLocalMap 属性 threadLocals , 类型是 ThreadLocal 的静态内部类
* //threadLocals 有 一 个 属 性 Entry[], 类 型
ThreadLocal.ThreadLocalMap.Entry
* //k-> ThreadLocal 对象 v-> 值
* ThreadLocalMap map = getMap(t);
* if (map != null)
* map.set(this, value);//存放这里的 this 就是 ThreadLocal, 可以 debug 源码,一目了然
* else
* createMap(t, value);//创建
}
threadLocal.set(dog);


3、ThreadLocal 可以像 Map 一样存取数据,key 为当前线程, get 方法获取当前线程的共享数据。

public T get() {
         *          //1. 先得到当前的线程对象
         *         Thread t = Thread.currentThread();
         *         //2.通过线程获取到对应的ThrealLocalMap
         *         ThreadLocalMap map = getMap(t);
         *         if (map != null) {
         *              //3. 如果map不为空, 根据当前的 threadlocal对象,得到对应的Entry
         *             ThreadLocalMap.Entry e = map.getEntry(this);
         *             //4. 如果e 不为null
         *             if (e != null) {
         *                 @SuppressWarnings("unchecked")
         *                 //返回当前threadlocal关联的数据value
         *                 T result = (T)e.value;
         *                 return result;
         *             }
         *         }
         *         return setInitialValue();
         *     }
         //获取ThrealLocalMap对象的Entry[] table里的当前线程对象的信息Entry(k,v)线程名和关联数据
          Object o = T1.threadLocal1.get();


4、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果不重新创建ThreadLocal对象实例,后面关联的对象会替换前面的对象。如果希望在当前线程共享多个数 据,就需要使用多个 ThreadLocal 对象实例。

threadLocal.set(dog);
//threadLocal.set(pig);//会替换 dog
//如果希望在同一个线程共享多个对象/数据,就在创建一个 ThreadLocal 对象
threadLocal2.set(pig);


  1. 5、每个 ThreadLocal 对象实例定义的时候,一般为 static 类型
  2. 6、ThreadLocal 中保存数据,在线程销毁后,会自动释放。


web 应用常用功能 -文件上传下载


1.文件的上传和下载,是常见的功能。

2.如果是传输大文件,一般有专门工具或者插件 。

3.文件上传下载需要使用到两个包 , 需要导入

24ce43585bca44f6891e1128a8126488.png


文件上传


1.使用表单提交。

//判断是不是文件表单(enctype="multipart/form-data")
  if (ServletFileUpload.isMultipartContent(request)) {
//是文件表单就构建创建解析上传数据的工具对象
//2. 创建 DiskFileItemFactory 对象, 用于构建一个解析上传数据的工具对象
  DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//3. 创建一个解析上传数据的工具对象
  ServletFileUpload servletFileUpload =new ServletFileUpload(diskFileItemFactory);}


2.action提交页面路径和之前一样,浏览器会自己解析前面的斜杠。


3.请求method指定为post。


4.enctype:encodetype编码类型默认是application/x-www-urlencodede即url编码,这种编码一般适用于文本。编码不正确会出现乱码。


5.进行二进制文件提交enctype要指定multipart/form-data 表示表单提交的数据有多个部分组成,可以提交二进制数据和文本数据。文件使用io技术进行处理。


文件上传注意事项和细节


1、如果文件上传会保存到一个目录下,当上传文件很多时,会造成访问文件速度变慢,因此 可以将文件上传到不同目录 比如 一天上传的文件,统一放到一个文件夹 年月日, 比如21001010 /文件名文件夹


2、一个完美的文件上传,要考虑的因素很多,比如断点续传、控制图片大小,尺寸,分片 上传,防止恶意上传等,在项目中,可以考虑使用 WebUploader 组件(百度开发) http://fex.baidu.com/webuploader/doc/index.html


3、文件上传功能,在项目中建议有限制的使用,一般用在头像、证明、合同、产品展示等, 如果不加限制,会造成服务器空间被大量占用 [比如 b 站评论,就不能传图片,微信发 1 次朋友圈最多 9 张图等…]


4、文件上传,创建 web/upload 的文件夹,在 tomcat 启动时,没有在 out 目录下 创建 对 应的 upload 文件夹, 原因是 tomcat 对应空目录是不会在 out 下创建相应目录的,所以,只 需在 upload 目录下,放一个文件即可, 这个是 Idea + Tomcat 的问题, 实际开发不会存 在.


文件下载


读取下载的文件数据,返回给客户端/浏览器

       //(1) 创建一个和要下载的文件,关联的输入流
        InputStream resourceAsStream =
                servletContext.getResourceAsStream(downLoadFileFullPath);
        //(2) 得到返回数据的输出流 [因为返回文件大多数是二进制(字节), IO java基础]
        ServletOutputStream outputStream = response.getOutputStream();
        //(3) 使用工具类,将输入流关联的文件,对拷到输出流,并返回给客户端/浏览器
        IOUtils.copy(resourceAsStream, outputStream);


文件下载注意事项和细节


  1. 1.文件下载,比较麻烦的就是文件名中有中文,需要进行处理。如果不处理编码就会出现乱码。设置编码后,浏览器得到文件名会使用相应方法进行解码,中文文件名就不会出现乱码。
// 获取到要下载的文件的名字
request.setCharacterEncoding("utf-8");
String downLoadFileName =request.getParameter("name");


2.不同的浏览器写法不一样,因此在代码中,我们要针对不同浏览器进行编码处理。

    //(1)如果是Firefox 则中文编码需要 base64
        //(2)Content-Disposition 是指定下载的数据的展示形式 , 如果attachment 则使用文件下载方式
        //(3)如果是其他(主流ie/chrome) 中文编码使用URL编码
        if (request.getHeader("User-Agent").contains("Firefox")) {
            // 火狐 Base64编码
            response.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" +
                    new BASE64Encoder().encode(downLoadFileName.getBytes("UTF-8")) + "?=");
        } else {
            // 其他(主流ie/chrome)使用URL编码操作
            response.setHeader("Content-Disposition", "attachment; filename=" +
                    URLEncoder.encode(downLoadFileName, "UTF-8"));
        }


  1. 3.对于网站的文件,很多文件使用另存为即可下载,对于大文件(文档,视频),会使用专 业的下载工具(迅雷、百度,腾讯,华为网盘等)。
  2. 4.对于不同的浏览器, 在把文件下载完毕后,处理的方式不一样, 有些是直接打开文件,有些是将文件下载到 本地/下载目录。
相关文章
|
2月前
|
消息中间件 监控 安全
服务Down机了,线程池中的数据如何保证不丢失?
在分布式系统与高并发应用开发中,服务的稳定性和数据的持久性是两个至关重要的考量点。当服务遭遇Down机时,如何确保线程池中处理的数据不丢失,是每一位开发者都需要深入思考的问题。以下,我将从几个关键方面分享如何在这种情况下保障数据的安全与完整性。
65 2
|
1月前
|
缓存 安全 Java
使用 Java 内存模型解决多线程中的数据竞争问题
【10月更文挑战第11天】在 Java 多线程编程中,数据竞争是一个常见问题。通过使用 `synchronized` 关键字、`volatile` 关键字、原子类、显式锁、避免共享可变数据、合理设计数据结构、遵循线程安全原则和使用线程池等方法,可以有效解决数据竞争问题,确保程序的正确性和稳定性。
41 2
|
2月前
|
消息中间件 存储 Java
服务重启了,如何保证线程池中的数据不丢失?
【8月更文挑战第30天】为确保服务重启时线程池数据不丢失,可采用数据持久化(如数据库或文件存储)、使用可靠的任务队列(如消息队列或分布式任务队列系统)、状态监测与恢复机制,以及分布式锁等方式。这些方法能有效提高系统稳定性和可靠性,需根据具体需求选择合适方案并进行测试优化。
197 5
|
3月前
|
Java
【Java集合类面试十二】、HashMap为什么线程不安全?
HashMap在并发环境下执行put操作可能导致循环链表的形成,进而引起死循环,因而它是线程不安全的。
|
3月前
|
安全 算法 Java
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
这篇文章讨论了Java集合类的线程安全性,列举了线程不安全的集合类(如HashSet、ArrayList、HashMap)和线程安全的集合类(如Vector、Hashtable),同时介绍了Java 5之后提供的java.util.concurrent包中的高效并发集合类,如ConcurrentHashMap和CopyOnWriteArrayList。
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
|
3月前
|
存储 安全 Java
解锁Java并发编程奥秘:深入剖析Synchronized关键字的同步机制与实现原理,让多线程安全如磐石般稳固!
【8月更文挑战第4天】Java并发编程中,Synchronized关键字是确保多线程环境下数据一致性与线程安全的基础机制。它可通过修饰实例方法、静态方法或代码块来控制对共享资源的独占访问。Synchronized基于Java对象头中的监视器锁实现,通过MonitorEnter/MonitorExit指令管理锁的获取与释放。示例展示了如何使用Synchronized修饰方法以实现线程间的同步,避免数据竞争。掌握其原理对编写高效安全的多线程程序极为关键。
64 1
|
3月前
|
数据处理 Python
解锁Python多线程编程魔法,告别漫长等待!让数据下载如飞,感受科技带来的速度与激情!
【8月更文挑战第22天】Python以简洁的语法和强大的库支持在多个领域大放异彩。尽管存在全局解释器锁(GIL),Python仍提供多线程支持,尤其适用于I/O密集型任务。通过一个多线程下载数据的例子,展示了如何使用`threading`模块创建多线程程序,并与单线程版本进行了性能对比。实验表明,多线程能显著减少总等待时间,但在CPU密集型任务上GIL可能会限制其性能提升。此案例帮助理解Python多线程的优势及其适用场景。
40 0
|
3月前
|
缓存 Java 容器
多线程环境中的虚假共享是什么?
【8月更文挑战第21天】
33 0
|
3月前
|
NoSQL Redis
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
45 1
C++ 多线程之初识多线程