Java——聊聊JUC中的ThreadLocal
文章目录:
1.什么是ThreadLocal?
1.1 api介绍
1.2 最简单的案例认识ThreadLocal
1.3 线程池结合ThreadLocal案例
2.Thread &ThreadLocal & ThreadLocalMap
3.ThreadLocal内存泄漏问题
3.1 四大引用之强引用
3.2 四大引用之软引用
3.3 四大引用之弱引用
3.4 四大引用之虚引用
3.5 ThreadLocal为什么是弱引用?
4.小总结
1.什么是ThreadLocal?
ThreadLocal提供线程局部变量,这些变量与正常的变量不同,因为每一个线程在访问ThreadLocal实例的时候(通过其get或set方法)都有自己的、独立初始化的变量副本。 ThreadLocal实例通常是类中的私有静态字段,使用它的目的是希望将状态(例如,用户ID或事务ID)与线程关联起来。
实现每一个线程都有自己专属的本地变量副本(自己用自己的变量不麻烦别人,不和其他人共享,人人有份,人各一份),主要解决了让每个线程绑定自己的值,通过使用get()和set()方法,获取默认值或将其值更改为当前线程所存的副本的值从而避免了线程安全问题。
1.1 api介绍
ThreadLocal是位于 java.lang 包下的,从jdk官方文档中可以看到它所有的api。而它的构造方法其实就是 withInitial(Supplier)。
1.2 最简单的案例认识ThreadLocal
希望各自分灶吃饭,各凭销售本事提成,按照出单数各自统计。比如某房产中介销售都有自己的销售额指标,自己专属于自己的,不和别人掺和。
使用ThreadLocal
先初始化,给个0值
利用set get方法
------注意,也要调用remove() 接口,不然容易导致内存泄漏。(在阿里巴巴Java开发手册中也有说明)
package com.juc.threadlocal;import java.util.Random;
import java.util.concurrent.TimeUnit;/*** @author: SongZiHao* @date: 2023/2/13*/
class House {public int saleCount = 0;public synchronized void saleHouse() {++saleCount;}// ThreadLocal<Integer> saleVolume = new ThreadLocal<Integer>() {
// @Override
// protected Integer initialValue() {
// return 0;
// }
// };ThreadLocal<Integer> saleVolume = ThreadLocal.withInitial(() -> 0);public void saleVolumeByThreadLocal() {saleVolume.set(saleVolume.get() + 1);}
}public class ThreadLocalDemo1 {public static void main(String[] args) {House house = new House();for (int i = 0; i < 5; i++) {new Thread(() -> {int size = new Random().nextInt(5) + 1;try {for (int j = 0; j < size; j++) {house.saleHouse();house.saleVolumeByThreadLocal();}System.out.println(Thread.currentThread().getName() + " 号销售卖出多少套:" + house.saleVolume.get());} finally {house.saleVolume.remove();}}, String.valueOf(i)).start();}try {TimeUnit.MILLISECONDS.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 共计卖出多少套:" + house.saleCount);}
}
1.3 线程池结合ThreadLocal案例
根据阿里规范,需要对自定义的ThreadLocal进行回收,否则容易造成内存泄漏和业务逻辑问题(因为线程池中的线程会复用)。
package com.juc.threadlocal;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author: SongZiHao* @date: 2023/2/13*/
class MyData {ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);public void add() {threadLocal.set(threadLocal.get() + 1);}
}public class ThreadLocalDemo2 {public static void main(String[] args) {MyData data = new MyData();ExecutorService threadPool = Executors.newFixedThreadPool(3);try {for (int i = 0; i < 10; i++) {threadPool.submit(() -> {try {Integer beforeValue = data.threadLocal.get();data.add();Integer afterValue = data.threadLocal.get();System.out.println(Thread.currentThread().getName() + " before: " + beforeValue + ", after: " + afterValue);} finally {data.threadLocal.remove();}});}} catch (Exception ex) {ex.printStackTrace();} finally {threadPool.shutdown();}}
}
如果上面的代码没有 finally + remove 了话,那么每个线程的value值就会累积,变成2、3、4等等,这是因为这些线程会被复用。
2.Thread &ThreadLocal & ThreadLocalMap
我们如果随便翻翻源码了话,可能会经常看到三个类:Thread,ThreadLocal,ThreadLocalMap。
根据官方API,Thread是程序中执行的线程;ThreadLocal类提供线程局部变量。
先打开
Thread.java
类,发现每个Thread类里面有一个ThreadLocal
类,而ThreadLocalMap
是ThreadLocal
的一个静态内部类。
下面是ThreadLocalMap这个静态内部类,熟悉HashMap的同学看到这里肯定不陌生,还是熟悉的配方、还是熟悉的味道,设置k-v键值对,初始化容量16。
threadLocalMap
实际上就是一个以threadLocal
实例为key,任意对象为value的Entry对象
。
当我们为threadLocal变量赋值,实际上就是以当前threadLocal实例为key,值为value的Entry往这个threadLocalMap中存放。JVM内部维护了一个线程版的Map<Thread, T>(通过ThreadLocal对象的set方法,结果把ThreadLocal对象自己当做key,放进了ThreadLoalMap中,每个线程要用到这个T的时候,用当前的线程去Map里面获取,通过这样让每个线程都拥有了自己独立的变量,人手一份,竞争条件被彻底消除,在并发模式下是绝对安全的变量。
每个Thread对象维护着一个ThreadLocalMap的引用。ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储。
- 调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值Value是传递进来的对象。
- 调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象。
- ThreadLocal本身并不存储值,它只是自己作为一个key来让线程从ThreadLocalMap获取value,正因为这个原理,所以ThreadLocal能够实现“数据隔离”,获取当前线程的局部变量值,不受其他线程影响。
Thread就是一个大活人,ThreadLocal就是身份证原件,ThreadLocalMap就是身份证上的信息(姓名:张三;出生年月:xxxx年y月z日)这不就是个k-v的Map吗?
那么Thread,ThreadLocal,ThreadLocalMap三者可以用下面这张图概括。
3.ThreadLocal内存泄漏问题
3.1 四大引用之强引用
Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
官方API: finalize()的通常目的是在对象被不可撤销地丢弃之前执行清理操作。(我自己理解,某个对象被干掉前还会调用finalize()清理一下)
- Reference是强引用
- SoftReference是软引用
- WeakReference是弱引用
- PhantomReference是虚引用
强引用:
- 当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收。
- 强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
- 对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,一般认为就是可以被垃圾收集的了(当然具体回收时机还是要看垃圾收集策略)。
package com.juc.threadlocal;import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** @author: SongZiHao* @date: 2023/2/13*/
class MyObject {//finalize方法一般不会重写,也不需要我们手动调用,这里为了演示案例才这样写@Overrideprotected void finalize() throws Throwable {//在对象被不可撤销的丢弃之前执行清理操作System.out.println("---- invoke finalize method ----");}
}public class ReferenceDemo {public static void main(String[] args) {strongReference();}/*** 默认模式:强引用*/private static void strongReference() {MyObject obj = new MyObject();System.out.println("gc before: " + obj);obj = null;System.gc(); //演示案例这里手动gc,一般不会这样做System.out.println("gc after: " + obj);}
}
3.2 四大引用之软引用
软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾收集。
对于只有软引用的对象来说,当系统内存充足时它 不会 被回收,当系统内存不足时它 会 被回收。
软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收!
演示案例先调整一下JVM的参数如下:👇👇👇
package com.juc.threadlocal;import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** @author: SongZiHao* @date: 2023/2/13*/
class MyObject {//finalize方法一般不会重写,也不需要我们手动调用,这里为了演示案例才这样写@Overrideprotected void finalize() throws Throwable {//在对象被不可撤销的丢弃之前执行清理操作System.out.println("---- invoke finalize method ----");}
}public class ReferenceDemo {public static void main(String[] args) {softReference();}/*** 软引用*/private static void softReference() {SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());System.out.println("gc before 内存够用: " + softReference.get());System.gc(); //演示案例这里手动gc,一般不会这样做try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("gc after 内存仍够用: " + softReference.get()); //软引用,gc之后内存够用就不会回收对象try {byte[] bytes = new byte[20 * 1024 * 1024]; //20MB对象,内存肯定不够用了} catch (Exception ex) {ex.printStackTrace();} finally {System.out.println("gc after 内存不够用: " + softReference.get()); //gc之后内存不够用就会回收对象}}
}
3.3 四大引用之弱引用
弱引用需要用java.lang.ref.WeakReference类来实现,它比软引用的生存期更短,
对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。
package com.juc.threadlocal;import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** @author: SongZiHao* @date: 2023/2/13*/
class MyObject {//finalize方法一般不会重写,也不需要我们手动调用,这里为了演示案例才这样写@Overrideprotected void finalize() throws Throwable {//在对象被不可撤销的丢弃之前执行清理操作System.out.println("---- invoke finalize method ----");}
}public class ReferenceDemo {public static void main(String[] args) {weakReference();}/*** 弱引用*/private static void weakReference() {WeakReference<MyObject> weakReference = new WeakReference<>(new MyObject());System.out.println("gc before 内存够用: " + weakReference.get());System.gc();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("gc after 内存够用: " + weakReference.get());}
}
3.4 四大引用之虚引用
- 虚引用必须和引用队列 (ReferenceQueue)联合使用。虚引用需要java.lang.ret.PhantomReterence类来实现,顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。
- PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被 finalize以后,做某些事情的通知机制。
- 处理监控通知使用,换句话说,设置虚引用关联对象的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理,用来实现比finalize机制更灵活的回收操作。
案例如下,记得先给JVM参数设置成
-Xms10m -Xmx10m
。
package com.juc.threadlocal;import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** @author: SongZiHao* @date: 2023/2/13*/
class MyObject {//finalize方法一般不会重写,也不需要我们手动调用,这里为了演示案例才这样写@Overrideprotected void finalize() throws Throwable {//在对象被不可撤销的丢弃之前执行清理操作System.out.println("---- invoke finalize method ----");}
}public class ReferenceDemo {public static void main(String[] args) {phantomReference();}/*** 虚引用*/private static void phantomReference() {MyObject obj = new MyObject();ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();PhantomReference<MyObject> phantomReference = new PhantomReference<>(obj, referenceQueue);System.out.println(phantomReference.get()); //虚引用get方法总是返回nullList<byte[]> list = new ArrayList<>();new Thread(() -> {while (true) {//一共10M内存,死循环每次向list中存1MB数据list.add(new byte[1 * 1024 * 1024]);try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(phantomReference.get() + " list add ok....");}}, "t1").start();new Thread(() -> {while (true) {Reference<? extends MyObject> reference = referenceQueue.poll();if (reference != null) {System.out.println("有虚对象被回收加入了队列....");break;}}}, "t2").start();}
}
由于这里的代码执行结果不一定会成功(打印有虚对象被回收加入了队列这句话),所以我直接把周阳老师的图抓了过来。
3.5 ThreadLocal为什么是弱引用?
当function01方法执行完毕后,栈帧销毁强引用 tl 也就没有了。但此时线程的ThreadLocalMap里某个entry的key引用还指向这个对象。
若这个key引用是强引用,就会导致key指向的ThreadLocal对象及v指向的对象不能被gc回收,造成内存泄漏;
若这个key引用是弱引用,就大概率会减少内存泄漏的问题。使用弱引用,就可以使ThreadLocal对象在方法执行完毕后顺利被回收且Entry的key引用指向为null。ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用引用他,那么系统gc的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话(比如正好用在线程池),这些key为null的Entry的value就会一直存在一条强引用链。
虽然弱引用,保证了key指向的ThreadLocal对象能被及时回收,但是v指向的value对象是需要ThreadLocalMap调用get、set时发现key为null时才会去回收整个entry、value,因此弱引用不能100%保证内存不泄露。我们要在不使用某个ThreadLocal对象后,手动调用方法来删除它,尤其是在线程池中,不仅仅是内存泄露的问题,因为线程池中的线程是重复使用的,意味着这个线程的ThreadLocalMap对象也是重复使用的,如果我们不手动调用remove方法,那么后面的线程就有可能获取到上个线程遗留下来的value值,造成bug。
- 结论:在不使用某个ThreadLocal对象后,手动调用remove方法来删除它(尤其是防止线程池下的复用)
- 从前面的set,get,remove方法的源码中可以看出,在threadLocal的生命周期里,针对threadLocal存在的内存泄漏的问题,都会通过expungeStaleEntry、cleanSomeSlots、replaceStaleEntry 这三个方法清理掉key为null的脏entry。
4.小总结
- 使用ThreadLocal一定要进行初始化,避免空指针问题。 ThreadLocal.withInitial(() -> 0)
建议把ThreadLocal修饰为static。
用完记得手动remove。
相关文章:
Java——聊聊JUC中的ThreadLocal
文章目录: 1.什么是ThreadLocal? 1.1 api介绍 1.2 最简单的案例认识ThreadLocal 1.3 线程池结合ThreadLocal案例 2.Thread &ThreadLocal & ThreadLocalMap 3.ThreadLocal内存泄漏问题 3.1 四大引用之强引用 3.2 四大引用之软引用 3.3 四…...
软件工程(4)--螺旋模型
前言 这是基于我所学习的软件工程课程总结的第四篇文章。 在软件开发过程中必须及时识别和分析风险,并且采取适当措施以消除或减少风险的危害。构建原型是一种能使某些类型的风险降至最低的方法。为了降低交付给用户的产品不能满足用户需要的风险,一种行…...
图解LeetCode——剑指 Offer 50. 第一个只出现一次的字符
一、题目 在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。 二、示例 2.1> 示例 1: 【输入】s "abaccdeff" 【输出】b 2.2> 示例 2: 【输入】s "" 【输出】 限制: 0 < s 的…...
《HTML 5与CSS 3核心技法》读书笔记
目录前言第1章 写在前面第2章 HTML 语法基础第3章 布局类元素 ,房子的楼板、柱子和大梁第4章 功能类元素,房子的门、窗、水管和电气第5章 CSS基础第6章 选择器,确定样式的作用范围选择器类型选择器的组合使用第7章 权重,样式发送冲…...
【沐风老师】3DMAX几何投影插件Geometry Projection使用详解
【几何投影插件】 描述 3DMAX几何投影插件Geometry Projection,将一个或多个对象或它的顶点选择沿全局或局部 x、y 或 z 轴投影到另一个对象上。 适用版本 3dMax2013或更高版本 安装设置 插件的安装非常简单,解压后把插件脚本 “geometry_projectio…...
面试问题整理
20200422面试题 1、有nginx为什么还要用gateway 2、factorybean和beanfactory有什么区别 https://www.cnblogs.com/leeego-123/p/12159574.html 2、aop原理 3、ioc原理 4、注解requestbody和responsebody区别。pathvireable和requestparam注解区别,feign客户端的注解…...
“区块链60人”2022赋能中国区块链创新人物名单公布
2022年11月5日,“2022第五届全国高校人工智能大数据区块链教育教学创新论坛”在京隆重召开。此次论坛公布了“区块链60人”2022赋能中国区块链创新人物评选活动获评名单。 本次评选活动通过媒体报道、第三方推荐、专家评选等环节,坚持“公开、公平、公正…...
day2324 数组
文章目录相关概念codeArrayTest08 数组拷贝相关概念 day23课堂笔记 1、数组 1.1、数组的优点和缺点,并且要理解为什么。 第一:空间存储上,内存地址是连续的。 第二:每个元素占用的空间大小相同。 第三:知道首元素的内…...
【Python实战】神仙运气—快看看你的彩票:2千多万元大奖无人领,马上就过期了,下一期的中奖者会是你吗?(纯技术交流)
前言 越努力越幸运 哈喽~我是栗子同学! 特别注意:不管是沉迷赌球,还是沉迷购彩,都是不可取的。本文纯是一个技术学习内容。 听说关注我的人会暴富哦!、 所有文章完整的素材源码都在👇👇 粉丝…...
2023年上半年软考高项信息系统项目管理师2月25日开班
信息系统项目管理师是全国计算机技术与软件专业技术资格(水平)考试(简称软考)项目之一,是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试,既属于国家职业资格考试,又是职称资…...
数据库(第一天)
文档信息 文档类别正式文档文档编号数据库基础课 1.2-001版本1.2-001文档名称数据库基础课编写负责人/编写时间梁昭东/2023 年 1 月 30 日审核负责人/审核时间年 月 日批准人/批准时间年 月 日 变更记录 日期版本号变更内容修订者2023.01.30v1.2版根据实际情况增删了部分内容…...
一文了解 ArrayList 的扩容机制
了解 ArrayList 在 Java 中常用集合类之间的关系如下图所示: 从图中可以看出 ArrayList 是实现了 List 接口,并是一个可扩容数组(动态数组),它的内部是基于数组实现的。它的源码定义如下: public class A…...
牛态已成选股源码
{牛态已成} {条件选股} {其他类型} N:7; A1:(REF(H,N) HHV(H,((2 * N) 1))); B1:FILTER(A1,N); C1:BACKSET(B1,(N 1)); D1:FILTER(C1,N); A2:(REF(L,N) LLV(L,((2 * N) 1))); B2:FILTER(A2,N); C2:BACKSET(B2,(N 1)); D2:FILTER(C2,N); E1:((REF(LLV(L,(2 * N)),1) REF(…...
Python基础
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。小编也整理了一套关于学习Python入门…...
浅显易懂的说清楚小游戏与H5游戏的技术区别
从“跳一跳”到“羊了个羊”微信小游戏上线4年时间,除了涌现出不少火爆全网的小游戏之外,也有类似于“动物餐厅”、“口袋奇兵”等游戏得以在此孵化繁荣,凭借着微信强大的社交属性小游戏成为游戏厂商在桌面端、App 端、H5 端之外争夺的另一个…...
【Python入门第七天】Python 数字
Python 数字 Python 中有三种数字类型: intfloatcomplex 为变量赋值时,将创建数值类型的变量: 实例 x 10 # int y 6.3 # float z 2j # complex如需验证 Python 中任何对象的类型,请使用 type() 函数: 实…...
Python自动化测试 软件测试最全教程(附笔记),看完可就业
最近看到很多粉丝在后台私信我,叫我做一期Python自动化测试的教程,其实关于这个问题,我也早就在着手准备了,我录制了一整套完整的Python自动化测试的教程,都上传在B站上面,大家有兴趣的可以去看一下&#x…...
Windows 安装Tomcat
版本:tomcat8.5jdk-8u231一.解压JDK安装包 更换JDK安装路径二.解压安装Tomcat 选择jdk安装路径更换tomcat安装路径三.设置环境变量 1.“环境变量”界面中系统变量点击”新建“,创建CATALINA_HOMEC:\RESSET\tomcat(Tomcat服务器的根目录)2.创建…...
知识图谱业务落地技术推荐之图数据库汇总
0.图数据库排名 链接:https://db-engines.com/en/ranking/graph+dbms 0.1简要分析(各种图数据库属性) Neo4j(主流) 历史悠久且...
2023新华为OD机试题 - 最小传递延迟(JavaScript) | 刷完必过
最小传递延迟 题目 通讯网络中有N个网络节点 用1 ~ N进行标识 网络通过一个有向无环图进行表示 其中图的边的值,表示节点之间的消息传递延迟 现给定相连节点之间的延时列表times[i]={u,v,w} 其中u表示源节点,v表示目的节点,w表示u和v之间的消息传递延时 请计算给定源节点到…...
SpringMVC基础入门(一)之理论基础概念
文章目录SpringMVC1.概念2.常用注解请求与响应1.请求参数2.JSON传输3.常用注解响应1.响应页面2.响应JSON数据Rest风格1.介绍2.常用注解SpringMVC 1.概念 (1)定义 SpringMVC是一种基于Java实现MVC模型的轻量级Web框架。 (2)为什…...
前端知识点
一. slice和splice区别: 1.splice改变原数组,slice不改变原数组。 2.splice除了可以删除之外,还可以插入。 3.splice可传入3个参数,slice接受2个参数。slice(start,end):方法可从已有数组中返回选定的元素,…...
【docker知识】从容器中如何访问到宿主机
一、说明 使用 Docker 能实现服务的容器化,并使用容器间网络在它们之间进行通信。有时您可能需要一个容器来与宿主机上非容器化的服务通信。以下是如何从 Docker 容器中访问本地主机或 127.0.0.1的具体方法。 二、方法1:简单的选择 适用于 Windows 和 Ma…...
MySQL入门篇-MySQL常用流程控制函数小结
备注:测试数据库版本为MySQL 8.0 这个blog我们来聊聊常见的流程控制函数 如需要scott用户下建表及录入数据语句,可参考:scott建表及录入数据sql脚本 流程控制函数 函数名函数用途CASEcase语句用于条件判断if()if/else条件判断ifnull()null数据处理nullif()retur…...
大数据技术架构(组件)35——Spark:Spark Streaming(1)
2.3、Spark Streaming2.3.0、OverviewSpark Streaming 是核心 Spark API 的扩展,它支持实时数据流的可扩展、高吞吐量、容错流处理。数据可以从许多来源(如 Kafka、Kinesis 或 TCP 套接字)获取,并且可以使用复杂的算法进行处理&am…...
实现超大文件上传逻辑
引言 文件上传功能是我们开发中经常会遇到的功能点,当日常开发中遇到小文件(比如:头像),可以直接将文件转为字节流直接上传到服务器上即可。但是当遇到大文件这种(比如:一部电影至少1个G)该怎么…...
JavaScript HTML DOM EventListener
JavaScript HTML DOM EventListener 是一个非常重要的概念,在前端开发中被广泛使用。它是用来监听 HTML DOM 上的事件,并执行特定的代码块。 EventListener 的语法非常简单,下面是一个示例代码: element.addEventListener("…...
构建RFID系统的重要组成部分
RFID读写设备,通常被用来扫描读取安装了RFID电子标签的目标物品,能实现快速批量无接触读写,是构建RFID系统的重要组成部分。RFID读写设备,通常有固定式读写设备和可移动读写设备两种。下面来了解一下RFID的特点,RFID系…...
PID控制算法简介
目录 1 简介 2 比例Proportional 3 积分Integral 4 微分Differential 5 公式 6 积分限幅 7 积分限行 8 相关代码 1 简介 PID控制中有P、I、D三个参数,PID即:Proportional(比例)、Integral(积分&#…...
【王道数据结构】第八章 | 排序
目录 8.1. 排序的基本概念 8.2. 插入排序 8.2.1. 直接插入排序 8.2.2. 折半插入排序 8.2.3. 希尔排序 8.3. 交换排序 8.3.1. 冒泡排序 8.3.2. 快速排序 8.4. 选择排序 8.4.1. 简单选择排序 8.4.2. 堆排序 8.5. 归并排序和基数排序 8.5.2. 基数排序 8.1. 排序的基本概念 排…...
广东知名网站/网站流量分析报告
我写了一个bash脚本,它在指定的文件夹中找到CSV文件,并使用正确的配置文件将它们管道到logstash中.但是,当运行此脚本时,我遇到以下错误,说关闭进程停止,导致无限循环,直到我用ctrl c手动停止它:[2018-03-22T08:59:53,833][INFO ][logstash.runner ] Starting Logst…...
容桂最新消息/吉林网络seo
1082. Read Number in Chinese (25) 时间限制400 ms内存限制65536 kB代码长度限制16000 B判题程序Standard作者CHEN, YueGiven an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese way. Output "Fu" first if it is ne…...
做外贸网站选美国服务器的费用/电商的运营模式有几种
过滤器的区别 捕捉过滤器(CaptureFilters):用于决定将什么样的信息记录在捕捉结果中。需要在开始捕捉前设置。显示过滤器(DisplayFilters):在捕捉结果中进行详细查找。他们可以在得到捕捉结果后随意修改。那…...
深圳国资委/seo流量的提升的软件
这里写目录标题下面是目录可跳转对应页面学习;1.MySQL环境1.1.环境安装1.2.安装位置1.3.修改字符集1.4.配置文件2.MySQL逻辑架构MySQL逻辑架构逻辑架构分层MySQL逻辑架构3.存储引擎下面是目录可跳转对应页面学习; 1. 简介 1.1 安装1.2 MySQL逻辑架构 1.…...
网站改版计划/今日国内新闻大事件
java基础之““ 与 ”equals ”的区别 前言: 作为Java的基础知识,我相信可能还有许多朋友对于 "" 与 "equals " 之间的关系还不是很明白,今天就总结一下两者的区别: 知识点一:“”与 equals 比…...
wordpress url 静态化/爱站网注册人查询
SQLiteOpenHelper类是Android提供的用于操作SQLite数据库的工具类,该工具类能方便地创建数据库、表,以及管理数据库版本。 常用方法 1、 synchronized SQLiteDatabase getReadableDatabase(); 作用:以读写的方式打开数据库对应的SQLiteDa…...