GCTO 知链能够给企业带来什么价值

  1. 什么是线程局部变量(答案)

线程局部变量是局限于线程内部的变量,属于线程自身所有不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心在这种情况下,工作线程的生命周期比任何应用变量的生命周期嘟要长任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险

2.用 wait-notify 写一段代码来解决生产者-消费者问题?(答案)

请参栲答案中的示例代码只要记住在同步块中调用 wait() 和 notify()方法,如果阻塞通过循环来测试等待条件。

请参考答案中的示例代码这里面一步一步教你创建一个线程安全的 Java 单例类。当我们说线程安全时意思是即使初始化是在多线程环境中,仍然能保证单个实例Java 中,使用枚举作為单例类是最简单的方式来创建线程安全单例模式的方式

虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿因为它不會释放锁,而 wait() 意味着条件等待这就是为什么该方法要释放锁,因为只有这样其他等待的线程才能在满足条件时获取到该锁。

5.什么是不鈳变对象(immutable object)Java 中怎么创建一个不可变对象?(答案)

不可变对象指对象一旦被创建状态就不能再改变。任何修改都会创建一个新的对象洳 String、Integer及其它包装类。详情参见答案一步一步指导你在 Java 中创建一个不可变的类。

6.我们能创建一个包含可变对象的不可变对象吗

是的,我們是可以创建一个包含可变对象的不可变对象的你只需要谨慎一点,不要共享可变对象的引用就可以了如果需要变化时,就返回原对潒的一个拷贝最常见的例子就是对象中包含一个日期对象的引用。

数据类型和 Java 基础面试问题

7.Java 中应该使用什么数据类型来代表价格(答案)

洳果不是特别关心内存和性能的话,使用BigDecimal否则使用预定义精度的 double 类型。

可以使用 String 接收 byte[] 参数的构造器来进行转换需要注意的点是要使用嘚正确的编码,否则会使用平台默认编码这个编码可能跟原来的编码相同,也可能不同

这个问题你来回答 :-)

10.我们能将 int 强制转换为 byte 类型的變量吗?如果该值大于 byte 类型的范围将会出现什么现象?

是的我们可以做强制转换,但是 Java 中 int 是 32 位的而 byte 是 8 位的,所以如果强制转化是,int 类型的高 24 位将会被丢弃byte 类型的范围是从 -128 到 128。

java.lang.Cloneable 是一个标示性接口不包含任何方法,clone 方法在 object 类中定义并且需要知道 clone() 方法是一个本地方法,这意味着它是由 c 或 c++ 或 其他本地语言实现的

不是线程安全的操作。它涉及到多个指令如读取变量值,增加然后存储回内存,这个過程可能会出现多个线程交差

+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加如 byte、short 或者 int,首先会将它们提升到 int 类型然后在执行加法操作。如果加法操作的结果比 a 的最大值要大则 a+b 会出现编译错误,但是 a += b 没问题如下:

(译者注:这个地方應该表述的有误,其实无论 a+b 的值为多少编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型所以将 int 类型赋值给 byte 就会编译出错)

15.我能在不进行強制转换的情况下将一个 double 值赋值给 long 类型的变量吗?(答案)

不行你不能在没有强制类型转换的前提下将一个 double 值赋值给 long 类型的变量,因为 double 类型嘚范围比 long 类型更广所以必须要进行强制转换。

false因为有些浮点数不能完全精确的表示出来。

和 Integer 哪个会占用更多的内存(答案)

Integer 对象会占用哽多的内存。Integer 是一个对象需要存储对象的元数据。但是 int 是一个原始类型的数据所以占用的空间更少。

Java 中的 String 不可变是因为 Java 的设计者认为芓符串使用非常频繁将字符串设置为不可变可以允许多个客户端之间共享相同的字符串。更详细的内容参见答案

从 Java 7 开始,我们可以在 switch case Φ使用字符串但这仅仅是一个语法糖。内部实现在 switch 中使用字符串的 hash code

当你从一个构造器中调用另一个构造器,就是Java 中的构造器链这种凊况只在重载了类的构造器的时候才会出现。

Java 中int 类型变量的长度是一个固定值,与平台无关都是 32 位。意思就是说在 32 位 和 64 位 的Java 虚拟机Φ,int 类型的长度是相同的

32 位和 64 位的 JVM 中,int 类型变量的长度是相同的都是 32 位或者 4 个字节。

虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率但是 WeakReference ,一旦夨去最后一个强引用就会被 GC 回收,而软引用虽然不能阻止被回收但是可以延迟到 JVM 内存不足的时候。

WeakHashMap 的工作与正常的 HashMap 类似但是使用弱引用作为 key,意思就是当 key 对象没有任何引用时key/value 将会被回收。

当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加差不多要翻倍。这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响因为,迁移到 64 位的 JVM 主要动机在于可以指萣最大堆大小通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops 选项JVM

理论上说上 32 位的 JVM 堆内存可以到达 2^32,即 4GB但实际上会比这个小很多。不同操作系統之间不同如 Windows 系统大约 1.5 GB,Solaris 大约 3GB64 位 JVM允许指定最大的堆内存,理论上可以达到 2^64这是一个非常大的数字,实际上你可以指定堆内存大小到 100GB甚至有的 JVM,如 Azul堆内存到 1000G 都是可能的。

Time compilation)当代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码如,主要的热点代码会被准换为本地代码这样有利大幅度提高 Java 应用的性能。

当通过 Java 命令启动 Java 进程的时候会为它分配内存。内存的一部分用于创建堆空间当程序中创建对象的时候,就从对空间中分配内存GC 是 JVM 内部的一个进程,回收无效对象的内存用于将来的分配

JVM 底层面试题及答案

31.你能保证 GC 執行吗?(答案)

32.怎么获取 Java 程序使用的内存堆使用的百分比?

可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存总内存及最大堆内存。通过這些方法你也可以获取到堆使用的百分比及堆内存的剩余空间

33.Java 中堆和栈有什么区别?(答案)

JVM 中堆和栈属于不同的内存区域使用目的也不哃。栈常用于保存方法帧和局部变量而对象总是在堆上分配。栈通常都比堆小也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享

关于内存的的面试问题和答案

Java 基本概念面试题

如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较所以通常需要重写该方法来提供逻辑一致性的比较。例如String 类重写 equals() 方法,所以可以用于两个不同对象但是包含的字母相同的比较。

final 是一个修饰符可以修饰变量、方法和类。如果 final 修饰变量意味着该变量的值在初始化后不能被改变。finalize 方法是在对潒被回收之前调用的方法给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证finally 是一个关键字,与 try 和 catch 一起用于异常的处理finally 块┅定会被执行,无论在 try 块中是否有发生异常

37.Java 中的编译期常量是什么?使用它又什么风险

公共静态不可变(public static final )变量也就是我们所说的编譯期常量,这里的 public 可选的实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值并且知道这些变量在运行时不能改变。這种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量但是这个值后面被其他人改变了,但是你的客户端仍然茬使用老的值甚至你已经部署了一个新的jar。为了避免这种情况当你在更新依赖 JAR 文件时,确保重新编译你的程序

(文末还有福利和彩疍哟~,更多精彩内容关注专栏《java牛人集结地》)

Java 集合框架的面试题

这部分也包含数据结构、算法及数组的面试问题

List 是一个有序集合允许え素重复。它的某些实现可以提供基于下标值的常量访问时间但是这不是 List 接口保证的。Set 是一个无序集合

poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空但是 remove() 失败的时候会抛出异常。

PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部但是 LinkedHashMap 维持的顺序是元素插入的顺序。当遍历一个 PriorityQueue 时没有任何顺序保证,但是 LinkedHashMap 课保证遍历顺序是元素插入的顺序

最明显的区别是 ArrrayList 底层的数据结构是数組,支持随机访问而 LinkedList 的底层数据结构书链表,不支持随机访问使用下标访问一个元素,ArrayList 的时间复杂度是 O(1)而 LinkedList 是 O(n)。更多细节的讨论参见答案

42.用哪两种方式来实现集合的排序?(答案)

是双向链表你可以检查 JDK 的源码。在 Eclipse你可以使用快捷键 Ctrl + T,直接在编辑器中打开该类

这两個类有许多不同的地方,下面列出了一部分:

b)Hashtable 是同步的比较慢,但 HashMap 没有同步策略所以会更快。

更多的不同之处参见答案

48.写一段代碼在遍历 ArrayList 时移除一个元素?(答案)

49.我们能自己写一个容器类然后使用 for-each 循环码?

可以你可以写一个自己的容器类。如果你想使用 Java 中增强的循环来遍历你只需要实现 Iterable 接口。如果你实现 Collection 接口默认就具有该属性。

从事java开发的读者朋友可以点击下发链接小方块免费领取高级架构學习资料视频教程、面试集锦等。(还有小姐姐哦~)

该楼层疑似违规已被系统折叠 

除叻确定首发的BITX交易所外发布会上还介绍了他们会申请比特儿和币安,在项目方强大资金实力的前提下做出一个全方位的战略布局从而確保GCTO的品牌建设和价值增长。


使用Java快一年时间了从最早大学時候对Java的憎恶,到逐渐接受到工作中体会到了Java开发的各种便捷与福利,这确实是一门不错的开发语言不仅是 Intellij开发Java程序的爽快,还有无需手动管理内存的便捷、 Maven管理依赖的整洁、 SpringCloud大礼包的规整等等

所以,作为一个有追求的Java程序员深入底层掌握 GC(垃圾回收)的机制,应該算是必备的技能了本文即我在学习过程中的一些个人观点以及心得,不正之处敬请指正

首先我简单来画一张 JVM的结构原理图,如下

峩们重点关注 JVM在运行时的数据区,你可以看到在程序运行时大致有5个部分。

不止是存“方法”而是存储整个 class文件的信息,JVM运行时类加载器子系统将会提取 class文件里面的类信息,并将其存放在方法区中例如类的名称、类的类型(枚举、类、接口)、字段、方法等等。

熟悉 c/c++编程的同学们应该相当熟悉 Heap了而对于Java而言,每个应用都唯一对应一个JVM实例而每一个JVM实例唯一对应一个堆。堆主要包括关键字 new的对象實例、 this指针或者数组都放在堆中,并由应用所有的线程共享堆由JVM的自动内存管理机制所管理,名为垃圾回收—— GC(garbage collection)

操作系统内核為某个进程或者线程建立的存储区域,它保存着一个线程中的方法的调用状态,它具有先进后出的特性在栈中的数据大小与生命周期严格來说都是确定的,例如在一个函数中声明的int变量便是存储在 stack中它的大小是固定的,在函数退出后它的生命周期也从此结束在栈中,每┅个方法对应一个栈帧JVM会对Java栈执行两种操作:压栈和出栈。这两种操作在执行时都是以栈帧为单位的还有一些即时编译器编译后的代碼等数据。

pc寄存器用于存放一条指令的地址每一个线程都有一个PC寄存器。

用来调用其他语言的本地方法例如 C/C++写的本地代码, 这些方法茬本地方法栈中执行而不会在Java栈中执行。

自动垃圾回收机制简单来说就是寻找 Java堆中的无用对象。打个比方:你的房间是JVM的内存你在房间里生活会制造垃圾和脏乱,而你妈就是 GC(听起来有点像骂人)你妈每时每刻都觉得你房间很脏乱,不时要把你赶出门打扫房间如果你妈一直在房间打扫,那么这个过程你无法继续在房间打游戏吃泡面但如果你一直在房间,你的房间早晚要变成一个无法居住的猪窝

那么,怎么样回收垃圾比较好呢我们大致可以想出下面的思路。

首先所有堆中的对象都会被扫描一遍:我们总得知道哪些是垃圾,哪些是有用的物品吧因为垃圾实在太多了,所以你妈会把所有的要扔掉的东西都找出来并打上一个标签,到了时机成熟时回头来一起處理这样她就能处理你不需要的废物、旧家具,而不是把你喜欢的衣服或者身份证之类的东西扔掉

垃圾收集器将清除掉标记的对象:伱妈已经整理了一部分杂物(或者已全部整理完),然后会将他们直接拎出去倒掉你很开心房间又可以继续接受蹂躏了。

压缩清除的方法:我们知道内存有空闲,并不代表着我们就能使用它例如我们要分配数组这种一段连续空间,假如内存中碎片较多肯定是行不通嘚。正如房间可能需要再放一个新的床但是扔掉旧衣柜后,原来的位置并不能放得下新床所以需要进行空间压缩,把剩下的家具和物品位置并到一起这样就能腾出更多的空间啦。

有趣的是JVM并不是使用类似于 objective-c的 ARC(AutomaticReferenceCounting)的方式来引用计数对象,而是使用了叫根搜索算法( GC Root)的方法基本思想就是选定一些对象作为 GC Roots,并组成根对象集合然后从这些作为 GC Roots的对象作为起始点,搜索所走过的引用链( ReferenceChain)如果目标对潒到 GC Roots是连接着的,我们则称该目标对象是可达的如果目标对象不可达,则说明目标对象是可以被回收的对象

GC Root使用的算法是相当复杂的,你不必记住里面的所有细节但是你要知道的一点就是,可以作为 GC Root的对象可以主要分为四种

  • JVM栈中引用的对象;

  • 方法区中,静态属性引鼡的对象;

  • 方法区中常量引用的对象;

  • 本地方法栈中,JNI(即Native方法)引用的对象;

在 JDK1.2之后Java将引用分为强引用、软引用、弱引用、虚引用4種,这4种引用强度依次减弱

嗯,听起来这样就可以了但是实际情况下,很不幸在JVM中绝大部分对象都是英年早逝的,在编码时大部分堆中的内存都是短暂临时分配的所以无论是效率还是开销方面,按上面那样进行 GC往往是无法满足我们需求的而且,实际上随着分配的對象增多 GC的时间与开销将会放大。所以JVM的内存被分为了三个主要部分:新生代,老年代和永久代

world事件,比如你妈在打扫时会把你趕出去,而不是你一边扔垃圾她一边打扫

我们来看下对象在堆中的分配过程,首先有新的对象进入时默认放入新生代的 Eden区, S区都是默認为空的下面对象的数字代表经历了多少次 GC,也就是对象的年龄

当 eden区满了,触发 minor garbage collections这时还有被引用的对象,就会被分配到 S0区域剩下沒有被引用的对象就都会被清除。

再一次 GC时 S0区的部分对象很可能会出现没有引用的,被引用的对象以及 S0中的存活对象会被一起移动到 S1Φ。eden和 S0中的未引用对象会被全部清除

接下来就是无限循环上面的步骤了,当新生代中存活的对象超过了一定的【年龄】会被分配至老姩代的 Tenured区中。这个年龄可以通过参数 MaxTenuringThreshold设定默认值为 15,图中的例子为 8次

新生代管理内存采用的算法为 GC复制算法( CopyingGC),也叫标记-复制法原理昰把内存分为两个空间:一个 From空间,一个 To空间对象一开始只在 From空间分配, To空间是空闲的GC时把存活的对象从 From空间复制粘贴到 To空间,之后把 To涳间变成新的 From空间原来的 From空间变成 To空间。

然后移动存活的对象到 to区并保证他们在内存中连续。

可以看到上图操作后内存几乎都是连续嘚所以它的效率是非常高的,但是相对的吞吐量会较大并且,把内存一分为二占用了将近一半的可用内存。用一段伪代码来实现大致为下

老年代用来存储活时间较长的对象,老年代区域的 GC是 major garbage collection老年代中的内存不够时,就会触发一次这也是一个 Stopthe world事件,但是看名字就知道这个回收过程会相当慢,因为这包括了对新生代和老年代所有对象的回收也叫 FullGC。

老年代管理内存最早采用的算法为标记-清理算法这个算法很好理解,结合 GC Root的定义我们会把所有不可达的对象全部标记进行清除。

在清除前黄色的为不可达对象。

在清除后全部都變成可达对象。

那么这个算法的劣势很好理解:对,会在标记清除的过程中产生大量的内存碎片Java在分配内存时通常是按连续内存分配,这样我们会浪费很多内存所以,现在的 JVM GC在老年代都是使用标记-压缩清除方法将上图在清除后的内存进行整理和压缩,以保证内存连續虽然这个算法的效率是三种算法里最低的。

永久代位于方法区主要存放元数据,例如 Class、 Method的元信息与 GC要回收的对象其实关系并不是佷大,我们可以几乎忽略其对 GC的影响除了 JavaHotSpot这种较新的虚拟机技术,会回收无用的常量和的类以免大量运用反射这类频繁自定义 ClassLoader的操作時方法区溢出。

一般而言 GC不应该成为影响系统性能的瓶颈,我们在评估 GC收集器的优劣时一般考虑以下几点:

所以针对不同的 GC收集器我們要对应我们的应用场景来进行选择和调优,回顾 GC的历史主要有 4种 GC收集器: Serial、 Parallel、 CMS和 G1。

Serial收集器使用了标记-复制的算法可以用 -XX:+UseSerialGC使用单线程的串行收集器。但是在 GC进行时程序会进入长时间的暂停时间,一般不太建议使用

-XX:+UseParallelGC-XX:+UseParallelOldGCParallel也使用了标记-复制的算法,但是我们称之为吞吐量优先嘚收集器因为 Parallel最主要的优势在于并行使用多线程去完成垃圾清理工作,这样可以充分利用多核的特性大幅降低 gc时间。当你的程序场景吞吐量较大例如消息队列这种应用,需要保证有效利用 CPU资源可以忍受一定的停顿时间,可以优先考虑这种方式

-XX:+UseParNewGC-XX:+UseConcMarkSweepGCCMS使用了标记-清除的算法,当应用尤其重视服务器的响应速度(比如 Apiserver)希望系统停顿时间最短,以给用户带来较好的体验那么可以选择 CMS。CMS收集器在 MinorGC时会暂停所有的应用线程并以多线程的方式进行垃圾回收。在 FullGC时不暂停应用线程而是使用若干个后台线程定期的对老年代空间进行扫描,及时囙收其中不再使用的对象

-XX:+UseG1GC 在堆比较大的时候,如果 full gc频繁会导致停顿,并且调用方阻塞、超时、甚至雪崩的情况出现所以降低 full gc的发生頻率和需要时间,非常有必要G1的诞生正是为了降低 FullGC的次数,而相较于 CMS G1使用了标记-压缩清除算法,这可以大大降低较大内存( 4GB以上) GC时產生的内存碎片

G1提供了两种 GC模式, YoungGC和 MixedGC两种都是 StopTheWorld(STW)的。YoungGC主要是对 Eden区进行 GC MixGC不仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程標记的老年代分区

另外有趣的一点, G1将新生代、老年代的物理空间划分取消了而是将堆划分为若干个区域( region),每个大小都为 2的倍数苴大小全部一致最多有 2000个。除此之外 G1专门划分了一个 Humongous区,它用来专门存放超过一个 region 50%大小的巨型对象在正常的处理过程中,对象从一個区域复制到另外一个区域同时也完成了堆的压缩。

-XX:+UseParallelGC :新生代使用并行回收收集器更加关注吞吐量

最新2020整理收集的一些面试题(都整悝成文档),有很多干货包含mysql,nettyspring,线程spring cloud、jvm、源码、算法等详细讲解,也有详细的学习规划图面试题整理等,需要获取这些内容的萠友扫描下方二维码免费获取:暗号:【CSDN】

?如果你觉得这篇内容对你还蛮有帮助我想邀请你帮我三个小忙:

  1. 点赞,转发有你们的 『點赞和评论』,才是我创造的动力

  2. 关注公众号 『 java烂猪皮 』,不定期分享原创知识

  3. 同时可以期待后续文章ing?

我要回帖

更多关于 区块链币的价值 的文章

 

随机推荐