대머리만이 당신을 강하게 만들 수 있습니다
저도 예전에 블로그를 하다가 글이 잘 쓰여진 블로그들이 소리 없이 모아지는 걸 발견했습니다. 최근 누락된 내용을 확인하고 있는데 상대적으로 중요한 지식 포인트가 있는데, 이전 블로그에 작성하지 않았기 때문에 여유 시간을 활용해 정리했습니다. (추천: JAVA 면접 질문 모음 ).
텍스트 지식 포인트:
정수 상수 풀
TCP 압축 해제 및 고정
select, poll, epoll
간단한 차이점select、poll、epoll
简单区别
jdk1.6以后对Synchronize锁优化
Java内存模型
本文力求简单讲清每个知识点,希望大家看完能有所收获
前阵子在群上看有人在讨论关于Integer的true或者false问题,我本以为我已经懂了这方面的知识点了。但还是做错了,后来去请教了一下朋友。朋友又给我发了另一张图:
后来发现这是出自《深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)》中的10.3.2小节中~
public class Main_1 { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L; System.out.println(c == d); System.out.println(e == f); System.out.println(c == (a + b)); System.out.println(c.equals(a + b)); System.out.println(g == (a + b)); System.out.println(g.equals(a + b)); System.out.println(g.equals(a + h)); } }
你们可以先思考一下再往下翻看答案,看看能不能做对。
在解这道题之前,相信很多人都已经知道了,在Java中会有一个Integer缓存池,缓存的大小是:-128~127
答案是:
true
false
true
true
true
false
true
简单解释一下:
使用==
的情况:
如果比较Integer变量,默认比较的是地址值。
Java的Integer维护了从-128~127
的缓存池
如果比较的某一边有操作表达式(例如a+b),那么比较的是具体数值
使用equals()
的情况:
无论是Integer还是Long中的equals()
默认比较的是数值。
Long的equals()
方法,JDK的默认实现:会判断是否是Long类型
注意自动拆箱,自动装箱问题。
反编译一下看看:
import java.io.PrintStream; public class Main_1 { public static void main(String[] paramArrayOfString) { Integer localInteger1 = Integer.valueOf(1); Integer localInteger2 = Integer.valueOf(2); Integer localInteger3 = Integer.valueOf(3); Integer localInteger4 = Integer.valueOf(3); Integer localInteger5 = Integer.valueOf(321); Integer localInteger6 = Integer.valueOf(321); Long localLong = Long.valueOf(3L); // 缓存池 System.out.println(localInteger3 == localInteger4); // 超出缓存池范围 System.out.println(localInteger5 == localInteger6); // 存在a+b数值表达式,比较的是数值 System.out.println(localInteger3.intValue() == localInteger1.intValue() + localInteger2.intValue()); // equals比较的是数值 System.out.println(localInteger3.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue()))); // 存在a+b数值表达式,比较的是数值 System.out.println(localLong.longValue() == localInteger1.intValue() + localInteger2.intValue()); // Long的equals()先判断传递进来的是不是Long类型,而a+b自动装箱的是Integer类型 System.out.println(localLong.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue()))); // ... 最后一句在这里漏掉了,大家应该可以推断出来 } }
我使用的反编译工具是jd-gui
public void vectorTest(){ Vector<String> vector = new Vector<String>(); for(int i = 0 ; i < 10 ; i++){ vector.add(i + ""); } System.out.println(vector); }
-128~127
true
<코드> 사용 == 사례:
Java의 정수는 -128~127
equals()
사용: 🎜🎜equals()
의 기본값은 🎜숫자 값🎜입니다. 🎜🎜🎜🎜Long의 equals()
메소드, JDK의 기본 구현: 🎜Long 유형인지 여부를 결정합니다🎜🎜🎜🎜🎜🎜자동 언박싱 및 자동 박싱 문제에 주의하세요. 🎜🎜🎜🎜 🎜🎜디컴파일하고 살펴보세요: 🎜rrreee🎜 제가 사용하는 디컴파일 도구는 jd-gui
입니다. 아직 디컴파일을 시도하지 않았다면 다운로드하여 사용할 수 있습니다. 🎜🎜🎜 🎜https: //github.com/java-decompiler/jd-gui/releases🎜🎜🎜🎜2. 동기화 잠금 최적화 방법은 무엇입니까? 멀티 스레딩 기사 리뷰: 🎜🎜🎜🎜ThreadLocal은 매우 간단합니다🎜🎜🎜🎜 멀티스레딩 3분이면 문 안으로 들어갈 수 있어요! 🎜🎜🎜🎜스레드 소스코드 분석🎜🎜🎜🎜멀티스레딩의 기본지식 포인트! 계속 읽어서 멀티스레딩을 배우고 절반의 노력으로 두 배의 결과를 얻으세요🎜🎜🎜🎜Java 잠금 메커니즘에 대해 알아보고🎜🎜🎜🎜AQS에 대해 알아보고 간단히 살펴보세요🎜🎜🎜🎜잠금 하위 클래스에 대해 알아보기🎜🎜🎜🎜 스레드 풀, 정말 배우고 싶지 않나요? 🎜🎜🎜🎜멀티쓰레드 교착상태는 참 간단해요🎜🎜🎜🎜자바 멀티스레딩을 도와주는 세 젊은이🎜🎜🎜🎜전에 멀티스레딩 글을 썼을 때, jdk1 이후에 동기화 잠금이 일어난다고 간략하게 말씀드렸습니다. 6 스핀 잠금, 잠금 제거, 잠금 조대화, 경량 잠금 및 바이어스 잠금에 대한 적응 등 다양한 최적화가 있습니다. 🎜🎜🎜🎜🎜이러한 최적화가 참 이해하기 어렵다고 생각했는데 사실~~간단한 이해로 이해하기 쉽습니다. 🎜🎜2.1 스핀 잠금에 적응🎜🎜잠금 경쟁은 커널 모드에서 사용자 모드에서 커널 모드로 🎜전환🎜을 거치게 되는데, 이는 꽤 시간이 많이 걸립니다. 🎜🎜🎜스핀 잠금🎜이 나타나는 이유는 대부분의 경우 🎜잠금 점유가 커널 모드로 전환하는 데 걸리는 시간보다 훨씬 짧은 시간🎜 동안만 지속되므로 스레드를 기다리게 하기 때문입니다. 커널 모드에 들어가기 전 제한된 시간, 이 시간 내에 잠금을 얻을 수 있으면 불필요한 시간을 많이 피할 수 있습니다. 그렇지 않은 경우 커널 모드에 들어가 잠금을 위해 경쟁합니다. 🎜🎜JDK 1.6에 적응형 스핀 잠금이 도입되었습니다. 이는 🎜회전 시간이 고정되지 않고 회전 여부가 점점 더 똑똑해진다🎜는 의미입니다. 🎜自旋锁在JDK1.4.2中就已经引入,只不过默认是关闭的,可以使用-XX:+UseSpinning
参数来开启,在JDK1.6中就已经改为默认开启了。
如果JVM明显检测到某段代码是线程安全的(言外之意:无锁也是安全的),JVM会安全地原有的锁消除掉!
比如说:
public void vectorTest(){ Vector<String> vector = new Vector<String>(); for(int i = 0 ; i < 10 ; i++){ vector.add(i + ""); } System.out.println(vector); }
Vector是默认加锁的,但JVM如果发现vector变量仅仅在vectorTest()
方法中使用,那该vector是线程安全的。JVM会把vector内部加的锁去除,这个优化就叫做:锁消除。
默认情况下,总是推荐将同步块的作用范围限制得尽量小。
但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,频繁地进行互斥同步操作也会导致不必要的性能损耗。
JVM会将加锁的范围扩展(粗化),这就叫做锁粗化。
轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。
如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销
但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。
简单来说:如果发现同步周期内都是不存在竞争,JVM会使用CAS操作来替代操作系统互斥量。这个优化就被叫做轻量级锁。
偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了!
偏向锁可以提高带有同步但无竞争的程序性能。它同样是一个带有效益权衡(Trade Off)性质的优化,也就是说,它并不一定总是对程序运行有利,如果程序中大多数的锁总是被多个不同的线程访问,那偏向模式就是多余的。在具体问题具体分析的前提下,有时候使用参数-XX:-UseBiasedLocking
来禁止偏向锁优化反而可以提升性能。
自适应偏向锁:自旋时间不固定
锁消除:如果发现代码是线程安全的,将锁去掉
锁粗化:加锁范围过小(重复加锁),将加锁的范围扩展
轻量级锁:在无竞争的情况下使用CAS操作去消除同步使用的互斥量
偏向锁:在无竞争环境下,把整个同步都消除,CAS也不做。
参考资料:
https://blog.csdn.net/chenssy/article/details/54883355
这是在看wangjingxin大佬面经的时候看到的面试题,之前对TCP粘包,拆包没什么概念,于是就简单去了解一下。
在进行Java NIO学习时,可能会发现:如果客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数据包粘在一起的情况。
TCP的首部格式:
TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;
从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段
基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。
一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包
接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包
拆包和粘包的问题导致接收端在处理的时候会非常困难(因为无法区分一个完整的数据包)
하위 포장 메커니즘에는 일반적으로 두 가지 공통 솔루션이 있습니다:
1, 특수 문자 제어
2, 헤더 대문자에 데이터 패킷 길이 추가
네티를 사용한다면 포장을 풀고 달라붙는 문제를 해결하기 위한 특수 인코더와 디코더가 있습니다.
팁:UDP에는 패킷 고착 문제가 없지만 패킷 손실 및 장애가 있습니다. 불완전한 패키지는 없으며, 수신된 모든 패키지는 완전히 정확합니다. 전송되는 데이터 단위 프로토콜은 UDP 메시지 또는 사용자 데이터그램이며 전송 시 병합되거나 분할되지 않습니다.
NIO 리뷰:
JDK10이 출시되었습니다. nio에 대해 얼마나 알고 계시나요?
Linux에서 I/O 재사용 모델을 구현하는 방법은 다음과 같습니다.
select/poll/epoll
함수 중 하나를 호출하고 여러 파일 설명자를 전달합니다. 파일 설명자가 준비되었습니다. 그렇지 않으면 시간 초과될 때까지 차단됩니다. select/poll/epoll
其中一个函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。
这几个函数是有些区别的,可能有的面试官会问到这三个函数究竟有什么区别:
区别如下图:
两句话总结:
select和poll
都需要轮询每个文件描述符,epoll
基于事件驱动,不用轮询
select和poll
每次都需要拷贝文件描述符,epoll
不用
select
最大连接数受限,epoll和poll
最大连接数不受限
tips:epoll在内核中的实现,用红黑树管理事件块
现在3y在公司里边实习,写完的代码需要给测试测一遍。
select/poll
情况:
开发在写代码,此时测试挨个问所有开发者,你写好程序了没有?要测试吗?
epoll
선택 및 설문 조사
각 파일 설명자를 폴링해야 합니다. epoll
은 이벤트 기반이며 폴링이 필요하지 않습니다
select and poll
은 매번 파일 설명자를 복사해야 합니다. epoll
은 사용되지 않습니다
select
최대 연결 수는 제한되어 있으며, epoll 및 poll
최대 연결 수는 제한되지 않습니다현재 3y는 회사에서 인턴으로 일하고 있으며 작성된 코드를 테스트해야 합니다.
select/poll
상황:
개발자가 코드를 작성하는 중입니다. 이때 테스트는 모든 개발자에게 하나씩
묻습니다. 프로그램 작성을 마쳤나요? 테스트하고 싶나요?
epoll
상황:
다른 인기 있는 설명 [1]:
기타 인기 있는 설명 [2]: 간단한 예를 들자면(별로 생생하지 않을 수도 있음) 선택/설문 조사 레스토랑 웨이터(커널)가 호텔 소유자(사용자 프로그램)에게 "지금 체크아웃하는 고객이 있습니다"라고 말하지만 아니요 이 웨이터를 아는 사람이 손님이 어떤 테이블에 돈을 지불하는지 상사에게 말하십시오. 사장님은 각 테이블에 가서 물어보세요: 지불하시겠습니까? epoll 호텔 웨이터(커널)가 호텔 주인(사용자 프로그램)에게 "1번, 2번, 5번 손님은 체크아웃하세요."라고 말합니다. 사장은 1번, 2번, 5번 테이블로 직접 가서 돈을 모을 수 있습니다
5. Java 메모리 모델JVM은 어떻게 시작에서 포기하게 되었나요?
JVM 메모리 구조와 Java 메모리 모델을 혼동한 적이 있었습니다~~~ 다행히 일부 열성적인 네티즌들이 지적해 주셨습니다.
JVM 메모리 구조:read(읽기): 메인 메모리 변수에 대해 작동하고, 후속 로드 작업에서 사용할 수 있도록 메인 메모리에서 스레드의 작업 메모리로 변수 값을 전송합니다.
load(로드) : 읽기 작업을 통해 주 메모리에서 얻은 변수 값을 작업 메모리의 변수 복사본에 저장하는 작업 메모리 변수에 작용합니다.
use(사용): 작업 메모리의 변수에 작용하여 작업 메모리의 변수 값을 실행 엔진에 전달합니다. 이는 가상 머신이 변수 값이 필요한 바이트코드 명령어를 발견할 때마다 실행됩니다. 작동하다.
할당(할당): 작업 메모리의 변수에 작용합니다. 실행 엔진에서 받은 값을 작업 메모리의 변수에 할당합니다. 이는 가상 머신이 값을 할당하는 바이트코드 명령어를 만날 때마다 실행됩니다. 변수로 작동합니다.
store(저장소): 작업 메모리의 변수에 작용하여 후속 쓰기 작업을 위해 작업 메모리의 변수 값을 주 메모리로 전송합니다.
write(쓰기): 메인 메모리의 변수에 대해 작업 메모리의 변수 값에서 메인 메모리의 변수로 저장 작업을 전송합니다.
Java 메모리 모델은 동시 프로세스에서 원자성, 가시성 및 순서를 처리하는 방법을 중심으로 구축되었습니다.
원자성을 보장하는 작업:
read、load、assign、use、store和write
동기화 잠금
보장하는 운영 질서(무질서한 결과 재정렬):
휘발성
동기화 잠금
가시성 보장:
휘발성
동기화 잠금
final
위에서도 언급했듯이, 휘발성 및 동기화 잠금을 통해 질서를 보장할 수 있지만 일반적으로 프로그램을 작성할 때 코드의 질서에 항상 주의를 기울이지는 않습니다. 실제로 Java에는 이전 발생 원칙(이전 발생)
작업 간 충돌 가능성과 관련된 모든 문제
작업은 이 규칙에 의해 정의된 범위 내에 있습니다. 작업 A가 작업 B보다 먼저 발생하도록 보장할 수 있습니다(재주문 문제는 없음)
위 내용은 자바 면접 질문 모음 - 쉽게 제안을 받는 데 도움이 되는 추천 면접 질문의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!