Java——ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法

文章目录

  • ①. ThreadLocal简介
    • ①. ThreadLocal是什么
    • ②. api介绍
    • ③. 永远的helloword
    • ④. 通过上面代码总结
  • ②. 从阿里ThreadLocal规范开始
    • ①. 非线程安全的SimpleDateFormat
    • ②. 将SimpleDateFormat定义成局部变量(方案一)
    • ③. ThreadLocal 解决日期格式乱码问题
    • ④. 阿里规范怎么说的?
  • ③. ThreadLocal源码分析
    • ①. Thread|ThreadLocal|ThreadLocalMap关系
    • ②. set方法详解
    • ③. get方法详解
    • ④. remove方法详解
  • ④. ThreadLocal内存泄漏问题
    • ①. 为什么源代码用弱引用?
    • ②. key为null的entry,原理解析
    • ③. set、get方法会去检查所有键为null的Entry对象
    • ④. 结论(在finally后面调用remove方法)
  • ⑤. ThreadLocal小总结

①. ThreadLocal简介

①. ThreadLocal是什么

①. ThreadLocal本地线程变量,线程自带的变量副本(实现了每一个线程副本都有一个专属的本地变量,主要解决的就是让每一个线程绑定自己的值,自己用自己的,不跟别人争抢。通过使用get()和set()方法,获取默认值或将其值更改为当前线程所存的副本的值从而避免了线程安全的问题)
②. synchronized或者lock,有个管理员,好比,现在大家签到,多个同学(线程),但是只有一只笔,只能同一个时间,只有一个线程(同学)签到,加锁(同步机制是以时间换空间,执行时间不一样,类似于排队)
在这里插入图片描述
③. ThreadLocal,人人有份,每个同学手上都有一支笔,自己用自己的,不用再加锁来维持秩序(同步机制是以空间换时间,为每一个线程都提供了一份变量的副本,从而实现同时访问,互不干扰同时访问,肯定效率高啊)
在这里插入图片描述

②. api介绍

  • ①. protected T initialValue?():initialValue():返回此线程局部变量的当前线程的"初始值"
    (对于initialValue()较为老旧,jdk1.8又加入了withInitial()方法)
  • ②. static ThreadLocal withInitial?(Supplier supplier):创建线程局部变量
  • ③. T get?():返回当前线程的此线程局部变量的副本中的值
  • ④. void set?(T value):将当前线程的此线程局部变量的副本设置为指定的值
  • ⑤. void remove?():删除此线程局部变量的当前线程的值

在这里插入图片描述

③. 永远的helloword

/**** 看每个销售员可以出售多少套房子*/
class House{/**initialValue():返回此线程局部变量的当前线程的"初始值"对于initialValue()较为老旧,jdk1.8又加入了withInitial()方法ThreadLocal<Integer>threadLocal=new ThreadLocal<Integer>() {@Overrideprotected Integer initialValue() {return 0;}};*///public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)//withInitial(Supplier<? extends S> supplier):创建线程局部变量//ThreadLocal本地线程变量,线程自带的变量副本ThreadLocal<Integer>threadLocal=ThreadLocal.withInitial(()->0);public void saleHouse(){//T get():返回当前线程的此线程局部变量的副本中的值。Integer value = threadLocal.get();value++;//void set(T value):将当前线程的此线程局部变量的副本设置为指定的值。threadLocal.set(value);}
}
public class ThreadLocalDemo {public static void main(String[] args) {House house = new House();new Thread(()->{try{for (int i = 1; i <=3; i++) {house.saleHouse();}System.out.println(Thread.currentThread().getName()+"\t"+"卖出:"+house.threadLocal.get());}catch (Exception e){e.getStackTrace();}finally {//void remove():删除此线程局部变量的当前线程的值//在阿里巴巴手册中有说明,尽量在代理中使用try-finally块进行回收house.threadLocal.remove();//下面获取到的值是线程的初始值0System.out.println("**********"+house.threadLocal.get());}},"t1").start();new Thread(()->{try{for (int i = 1; i <=5; i++) {house.saleHouse();}System.out.println(Thread.currentThread().getName()+"\t"+"卖出:"+house.threadLocal.get());}catch (Exception e){e.getStackTrace();}finally {house.threadLocal.remove();}},"t2").start();new Thread(()->{try{for (int i = 1; i <=8; i++) {house.saleHouse();}System.out.println(Thread.currentThread().getName()+"\t"+"卖出:"+house.threadLocal.get());}catch (Exception e){e.getStackTrace();}finally {house.threadLocal.remove();}},"t3").start();System.out.println(Thread.currentThread().getName()+"\t"+"卖出了:"+house.threadLocal.get());}
}
/*** t1	卖出:3* t2	卖出:5* **********0* main	卖出了:0* t3	卖出:8* */

④. 通过上面代码总结

  • ①. 因为每个Thread内有自己的实例副本且该副本只由当前线程自己使用
  • ②. 既然其他Thread不可访问,那就不存在多线程共享的问题
  • ③. 统一设置初始值,但是每个线程对这个值的修改都是各自线程互相独立的
  • ④. 加入synchronized或者lock控制线程的访问顺序,而ThreadLocal人手一份,大家各自安好,没必要抢夺

②. 从阿里ThreadLocal规范开始

①. 公司业务:在对一些业务日志写入数据库的时候,日期调用了sdf的静态,导致了会报错或者日期乱了(生产故障)

在这里插入图片描述

①. 非线程安全的SimpleDateFormat

  • ①. 写时间工具类,一般写成静态的成员变量,不知,此种写法的多线程下的危险性!
  • ②. 代码展示
public class DateUtils
{public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/*** 模拟并发环境下使用SimpleDateFormat的parse方法将字符串转换成Date对象* @param stringDate* @return* @throws Exception*/public static Date parseDate(String stringDate)throws Exception{return sdf.parse(stringDate);}public static void main(String[] args) throws Exception{for (int i = 1; i <=30; i++) {new Thread(() -> {try {System.out.println(DateUtils.parseDate("2020-11-11 11:11:11"));} catch (Exception e) {e.printStackTrace();}},String.valueOf(i)).start();}}
}
  • ③. bug
    在这里插入图片描述
  • ④. 源码分析结论(了解)
    SimpleDateFormat类内部有一个Calendar对象引用,它用来储存和这个SimpleDateFormat相关的日期信息,例如sdf.parse(dateStr),sdf.format(date) 诸如此类的方法参数传入的日期相关String,Date等等, 都是交由Calendar引用来储存的.这样就会导致一个问题如果你的SimpleDateFormat是个static的, 那么多个thread 之间就会共享这个SimpleDateFormat, 同时也是共享这个Calendar引用

在这里插入图片描述在这里插入图片描述

②. 将SimpleDateFormat定义成局部变量(方案一)

  • 缺点:每调用一次方法就会创建一个SimpleDateFormat对象,方法结束又要作为垃圾回收
public class DateUtils
{public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/*** 模拟并发环境下使用SimpleDateFormat的parse方法将字符串转换成Date对象* @param stringDate* @return* @throws Exception*/public static Date parseDate(String stringDate)throws Exception{return sdf.parse(stringDate);}public static void main(String[] args) throws Exception{for (int i = 1; i <=30; i++) {new Thread(() -> {try {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(sdf.parse("2020-11-11 11:11:11"));sdf = null;} catch (Exception e) {e.printStackTrace();}},String.valueOf(i)).start();}}

③. ThreadLocal 解决日期格式乱码问题

/*** 在对一些业务日志写入数据库的时候,日期调用了sdf的静态,导致了会报错或者日期乱了* */
public class ThreadLocalDataUtils {public static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/**解决方案一:加入synchronized,用时间换空间,效率低*//**如果不加会导致线程安全问题,SimpleDateFormat类内部有一个Calendar对象引用,SimpleDateFormat相关的日期信息,例如sdf.parse(dateStr),sdf.format(date)诸如此类的方法参数传入的日期相关String,Date等等, 都是交由Calendar引用来储存的.这样就会导致一个问题如果你的SimpleDateFormat是个static的,那么多个thread之间就会共享这个SimpleDateFormat,同时也是共享这个Calendar引用(相当于买票案列)*///public static synchronized Date parse(String stringDate) throws ParseException {public static  Date parse(String stringDate) throws ParseException {System.out.println(sdf.parse(stringDate));return sdf.parse(stringDate);}/**** 解决方案二:使用ThreadLocal,用空间换时间,效率高* ThreadLocal中变量副本会人手一份,每次使用完了threadLocal后都要将资源进行释放的处理*/public static final ThreadLocal<SimpleDateFormat>sdfThreadLocal=ThreadLocal.withInitial(()->new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));public static  Date parseByThreadLocal(String stringDate) throws ParseException {return sdfThreadLocal.get().parse(stringDate);}//3 DateTimeFormatter 代替 SimpleDateFormatpublic static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");public static String formatForDateTime(LocalDateTime localDateTime) {return DATE_TIME_FORMAT.format(localDateTime);}public static LocalDateTime parseForDateTime(String dateString) {return LocalDateTime.parse(dateString,DATE_TIME_FORMAT);}public static void main(String[] args) throws Exception{for (int i = 1; i <=3; i++) {new Thread(()->{try {//ThreadLocalDataUtils.parse("2021-03-30 11:20:30");//System.out.println(ThreadLocalDataUtils.parseByThreadLocal("2021-03-30 11:20:30"));System.out.println(ThreadLocalDataUtils.parseForDateTime("2021-03-30 11:20:30"));// System.out.println(ThreadLocalDataUtils.formatForDateTime(LocalDateTime.now()));} catch (Exception e) {e.printStackTrace();}finally {ThreadLocalDataUtils.sdfThreadLocal.remove();}},String.valueOf(i)).start();}}
}

④. 阿里规范怎么说的?

在这里插入图片描述

③. ThreadLocal源码分析

①. Thread|ThreadLocal|ThreadLocalMap关系

①. Thread和ThreadLocal
在这里插入图片描述
②. ThreadLocal和ThreadLocalMap
在这里插入图片描述
③. All三者总概括

  1. Thread类中有一个ThreadLocal.ThreadLocalMap threadLocals = null的变量,这个ThreadLocal相当于是Thread类和ThreadLocalMap的桥梁,在ThreadLocal中有静态内部类ThreadLocalMap,ThreadLocalMap中有Entry数组
  2. 当我们为threadLocal变量赋值,实际上就是以当前threadLocal实例为key,值为value的Entry往这个threadLocalMap中存放
  3. t.threadLocals = new ThreadLocalMap(this, firstValue) 如下这行代码,可以知道每个线程都会创建一个ThreadLocalMap对象,每个线程都有自己的变量副本
    在这里插入图片描述
//核心代码说明
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);
}

②. set方法详解

①. 首先获取当前线程,并根据当前线程获取一个Map
②. 如果获取的Map不为空,则将参数设置到Map中(当前ThreadLocal的引用作为key)
③. 如果Map为空,则给该线程创建 Map,并设置初始值

 /*** 设置当前线程对应的ThreadLocal的值** @param value 将要保存在当前线程对应的ThreadLocal的值*/public void set(T value) {// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 判断map是否存在if (map != null)// 存在则调用map.set设置此实体entrymap.set(this, value);else// 1)当前线程Thread 不存在ThreadLocalMap对象// 2)则调用createMap进行ThreadLocalMap对象的初始化// 3)并将 t(当前线程)和value(t对应的值)作为第一个entry存放至ThreadLocalMap中createMap(t, value);}/*** 获取当前线程Thread对应维护的ThreadLocalMap * * @param  t the current thread 当前线程* @return the map 对应维护的ThreadLocalMap */ThreadLocalMap getMap(Thread t) {return t.threadLocals;}/***创建当前线程Thread对应维护的ThreadLocalMap ** @param t 当前线程* @param firstValue 存放到map中第一个entry的值*/void createMap(Thread t, T firstValue) {//这里的this是调用此方法的threadLocalt.threadLocals = new ThreadLocalMap(this, firstValue);}/** firstKey : 本ThreadLocal实例(this)* firstValue : 要保存的线程本地变量*/ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {//初始化tabletable = new ThreadLocal.ThreadLocalMap.Entry[INITIAL_CAPACITY];//计算索引(重点代码)int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//设置值table[i] = new ThreadLocal.ThreadLocalMap.Entry(firstKey, firstValue);size = 1;//设置阈值setThreshold(INITIAL_CAPACITY);}

③. get方法详解

  • 先获取当前线程的ThreadLocalMap变量,如果存在则返回值,不存在则创建并返回初始值
  /*** 返回当前线程中保存ThreadLocal的值* 如果当前线程没有此ThreadLocal变量,* 则它会通过调用{@link #initialValue} 方法进行初始化值** @return 返回当前线程对应此ThreadLocal的值*/public T get() {// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 如果此map存在if (map != null) {// 以当前的ThreadLocal 为 key,调用getEntry获取对应的存储实体eThreadLocalMap.Entry e = map.getEntry(this);// 对e进行判空 if (e != null) {@SuppressWarnings("unchecked")// 获取存储实体 e 对应的 value值// 即为我们想要的当前线程对应此ThreadLocal的值T result = (T)e.value;return result;}}/*初始化 : 有两种情况有执行当前代码第一种情况: map不存在,表示此线程没有维护的ThreadLocalMap对象第二种情况: map存在, 但是没有与当前ThreadLocal关联的entry*/return setInitialValue();}/*** 初始化** @return the initial value 初始化后的值*/private T setInitialValue() {// 调用initialValue获取初始化的值// 此方法可以被子类重写, 如果不重写默认返回nullT value = initialValue();// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 判断map是否存在if (map != null)// 存在则调用map.set设置此实体entrymap.set(this, value);else// 1)当前线程Thread 不存在ThreadLocalMap对象// 2)则调用createMap进行ThreadLocalMap对象的初始化// 3)并将 t(当前线程)和value(t对应的值)作为第一个entry存放至ThreadLocalMap中createMap(t, value);// 返回设置的值valuereturn value;

④. remove方法详解

①. 首先获取当前线程,并根据当前线程获取一个Map
②. 如果获取的Map不为空,则移除当前ThreadLocal对象对应的entry

 	/*** 删除当前线程中保存的ThreadLocal对应的实体entry*/public void remove() {// 获取当前线程对象中维护的ThreadLocalMap对象ThreadLocalMap m = getMap(Thread.currentThread());// 如果此map存在if (m != null)// 存在则调用map.remove// 以当前ThreadLocal为key删除对应的实体entrym.remove(this);}

④. ThreadLocal内存泄漏问题

①. 为什么源代码用弱引用?

①. 当function01方法执行完毕后,栈帧销毁强引用 tl 也就没有了。但此时线程的ThreadLocalMap里某个entry的key引用还指向这个对象
②. 若这个key引用是强引用,就会导致key指向的ThreadLocal对象及v指向的对象不能被gc回收,造成内存泄漏
③. 若这个key引用是弱引用就大概率会减少内存泄漏的问题(还有一个key为null的雷)。使用弱引用,就可以使ThreadLocal对象在方法执行完毕后顺利被回收且Entry的key引用指向为null
在这里插入图片描述

②. key为null的entry,原理解析

  • ①. 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对象后,手动调用remoev方法来删除它,尤其是在线程池中,不仅仅是内存泄露的问题,因为线程池中的线程是重复使用的,意味着这个线程的ThreadLocalMap对象也是重复使用的,如果我们不手动调用remove方法,那么后面的线程就有可能获取到上个线程遗留下来的value值,造成bug
  • ④. 如果当前thread运行结束,threadLocal,threadLocalMap, Entry没有引用链可达,在垃圾回收的时候都会被系统进行回收
  • ⑤. 但在实际使用中我们有时候会用线程池去维护我们的线程,比如在Executors.newFixedThreadPool()时创建线程的时候,为了复用线程是不会结束的,所以threadLocal内存泄漏就值得我们小心
    在这里插入图片描述
  • ⑥. 出现内存泄漏的真实原因 (1). 没有手动删除这个Entry (2). CurrentThread依然运行

③. set、get方法会去检查所有键为null的Entry对象

①. set( )
在这里插入图片描述在这里插入图片描述 ②. get( )
在这里插入图片描述
在这里插入图片描述
③. remove( )
在这里插入图片描述

④. 结论(在finally后面调用remove方法)

在这里插入图片描述

⑤. ThreadLocal小总结

  • ①. ThreadLocal本地线程变量,以空间换时间,线程自带的变量副本,人手一份,避免了线程安全问题
  • ②. 每个线程持有一个只属于自己的专属Map并维护了Thread Local对象与具体实例的映射,该Map由于只被持有它的线程访问,故不存在线程安全以及锁的问题
  • ③. ThreadLocalMap的Entry对ThreadLocal的引用为弱引用,避免了ThreadLocal对象无法被回收的问题
  • ④. 都会通过expungeStaleEntry,cleanSomeSlots, replace StaleEntry这三个方法回收键为 null 的 Entry 对象的值(即为具体实例)以及 Entry 对象本身从而防止内存泄漏,属于安全加固的方法
  • ⑤. 用完之后一定要remove操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JPA入门

文章目录JPA概述JPASpring Data JPAJPA注解基础注解EntityTableIdEnumeratedTransientColumnTemporal联合主键注解IdClassEmbeddable和EmbeddedId注解实体之间关联关系注解OneToOneManyToOne和OneToManyRepositoryJPA查询方式DQM&#xff08;定义查询方法&#xff09;使用实例D…

Java8——Stream流操作List排序_List集合中每个对象元素按时间顺序排序

一个学生类的实体类 Data public class Student {private Long id;private String name;private int age;private Double height;public Student(Long id, String name, int age, Double height) {this.id id;this.name name;this.age age;this.height height;}然后我们测…

java线程初始方法三种_Java 多线程 三种实现方式

Java多线程实现方式主要有三种&#xff1a;继承Thread类、实现Runnable接 口、使用ExecutorService、Callable 实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值&#xff0c;只有最后一种Callable是带返回值的&#xff0c;返回结果可以从Future中取出来关于Exe…

java控制层创建websocket_用Java构建一个简单的WebSocket聊天室

前言首先对于一个简单的聊天室&#xff0c;大家应该都有一定的概念了&#xff0c;这里我们省略用户模块的讲解&#xff0c;而是单纯的先说说聊天室的几个功能&#xff1a;自我对话、好友交流、群聊、离线消息等。今天我们要做的demo就能帮我们做到这一点啦&#xff01;&#xf…

Java中Date与 LocalDateTime ,LocalDate之间的转换

Date与LocalDateTime和LocalDate互相转换思路 Date转LocalDateTime和LocalDate都可以通过Date先转换成Instant然后再转换成LocalDateTime和LocalDate&#xff0c;可以按照下图的方式进行转换。LocalDateTime和LocalDate转换成Date也是以Instant为中介来进行转换的。 1&#xff…

Spring-data-jpa入门(一)

啥是JPA 我这个小白没有听说过&#xff0c;全英文名叫Java Persistence API&#xff0c;就是java持久化api&#xff0c;是SUN公司推出的一套基于ORM的规范。 持久化想必如雷贯耳&#xff0c;都2022年了&#xff0c;谁还不用个持久化框架啊&#xff0c;举起mybatis。 ORM呢&a…

struts单例模式 java_Java单例设计模式详细介绍

Java单例设计模式教程中包含了单例模式的定义、特点以及线路安全等问题。单例模式定义&#xff1a;单例模式确保某个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这个实例。在计算机系统中&#xff0c;线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对…

NetBeans、Eclipse 和 IDEA,哪个才是最优秀的Java IDE?

NetBeans、Eclipse 和 IDEA&#xff0c;哪个才是最优秀的Java IDE? 本文将向您介绍三种流行的Java IDE的基本特点&#xff0c;并比较它们的优缺点。 众所周知&#xff0c;集成开发环境(IDE)能够让程序员的日常编程过程&#xff0c;比起直接在文本编辑器上编写代码要容易得多。…

Spring-data-jpa入门(二)

前言 上一节我们讲解了spring-data-jpa最基础的架构和最简单的增删查改的实现&#xff0c;可以发现spring-data-jpa在简单增删查改的实现是非常友好的&#xff0c;甚至根本见不着sql语句的存在&#xff0c;让人直呼NB。 还记得上一节埋的几个坑吗&#xff0c;这一节就先把坑填…

JavaWeb学习笔记——详细

一、HTTP协议简介 1、什么是http协议 概述&#xff1a; HTTP是Hyper Text Transfer Protocol的缩写&#xff0c;即超文本传输协议。它是一种请求/响应式的协议&#xff0c;客户端在与服务器端建立连接后就可以向服务器端发送请求&#xff0c;这种请求被称作HTTP请求&#xf…

基本数据类型和包装类的区别,编程中如何选择?

问题&#xff1a;基本数据类型和包装类有什么区别吧&#xff0c;什么时候用包装类什么时候用基本数据类型&#xff1f; 最本质的区别&#xff1a;基本数据类型不是对象&#xff0c;包装类型是对象存储位置不同&#xff1a;基本类型是直接将变量值存储在栈中&#xff0c;而包装…

java怎么获取控制台内容的类型_java 怎么获取控制台的数据并且输出到GUI上

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼以前做过&#xff0c;给个参考。为防止格式错乱&#xff0c;以下代码用base64解码一下得到格式良好的代码。aW1wb3J0IG9yZy5qdW5pdC5UZXN0OwoKaW1wb3J0IGphdmEuaW8uKjsKaW1wb3J0IGphdmEudXRpbC5BcnJheUxpc3Q7CmltcG9ydCBqYXZhLnV0a…

描述一下JAVA的加载过程_JVM源码分析之Java类的加载过程

简书 占小狼转载请注明原创出处&#xff0c;谢谢&#xff01;趁着年轻&#xff0c;多学习背景最近对Java细节的底层实现比较感兴趣&#xff0c;比如Java类文件是如何加载到虚拟机的&#xff0c;类对象和方法是以什么数据结构存在于虚拟机中&#xff1f;虚方法、实例方法和静态方…

MongoDB 官方云端使用方法

MongoDB介绍 MongoDB是一种面向文档型的非关系型数据库&#xff08;NoSQL&#xff09;&#xff0c;由C编写。非关系数据库中是以键值对存储&#xff0c;结构不固定&#xff0c;易存储&#xff0c;减少时间和空间的开销。文档型数据库通常是以JSON或XML格式存储数据&#xff0c…

java cpu io高_服务器负载过高问题分析-不是cpu高负载也不是IO负载如何处理(阿里 几乎是必考题)...

关于top命令 经常问load average 参考&#xff1a;load average 定义(网易面试)问题现象&#xff1a;1&#xff0c;top命令查询服务器负载达到2.0-5之间&#xff0c;tomcat的cpu使用率达到104%load average:linux系统中的Load对当前CPU工作量的度量。简单的说是进程队列的长度。…

MaxCompute开发笔记——快速入门

前提条件 请确保以下工作已经完成&#xff1a; 开通阿里云账号。 购买MaxCompute。 创建要使用的项目空间&#xff0c;详情请参见创建空间。如果要使用的项目空间已存在&#xff0c;请确保已被添加至此项目空间并被赋予建表等权限。 完成客户端安装配置。 导入数据 Tunn…

java中android_在Android中用纯Java代码布局

本文的完成了参考了一篇国外的教程,在此表示感谢。Android中的界面布局主要有两种方式&#xff0c;一种是xml文件和Java代码结合的布局方式&#xff0c;一种是完全依靠Java代码布局。两种布局方式的比较对于第一种方式&#xff0c;大多数人都比较熟悉&#xff0c;在这里就不细说…

DataWorks概述

文章目录一、DataWorks概况1.1 定义1.2 功能1.3 与MaxCompute的关系二、基于DataWorks与MaxCompute构建云数仓一站式大数据开发治理DataWorks学习DataWorks 是什么&#xff1f;产品定位产品受众核心能力数据治理的概念、需求层次和目标对于数据治理概念的一些基本理解数据治理的…

Dataworks的使用——详细说明

一、开通Dataworks &#xff08;1&#xff09;百度搜Dataworks&#xff0c;进入如下页面&#xff0c;点击立即开通 &#xff08;2&#xff09; 这里要选好自己想要的配置&#xff0c;这里展示我之前的配置 解决方案&#xff1a;选DataWorksMaxCompute组合产品 DataWorks&…

DataWorks快速入门

快速入门 入门概述 说明 如果您是第一次使用DataWorks&#xff0c;请确认已经根据准备工作模块的操作&#xff0c;准备好账号和工作空间角色等内容后&#xff0c;登录DataWorks控制台&#xff0c;单击相应工作空间后的进入数据开发&#xff0c;即可进行数据开发操作。本模块的…