머리말
이것은이 기간 동안 매우 유휴 상태이므로 JDK 소스 코드를 보았습니다. 일반 선임 개발 엔지니어는 일부 소스 코드를 읽음으로써 자신을 향상시킬 수 있습니다. 이 기사는 JDK 소스 코드의 "작은 팁"을 요약하고 참조 및 학습을 위해 공유합니다. 나는 아래에서 많이 말하지 않을 것입니다. 자세한 소개를 함께 살펴 보겠습니다.
1 i ++ vs i--
문자열 소스 코드의 985 행
while (n-! = 0) {if (v1 [i]! = v2 [i]) false를 반환합니다. i ++; }이 코드는 문자열이 동일인지 판단하는 데 사용되지만 판단을하기 위해 i-! = 0을 사용하는 이상한 것은 있습니다. 우리는 보통 i ++를 사용하지 않습니까? 왜 I-? 그리고 사이클 수는 동일합니다. 그 이유는 컴파일 후 하나 더 지침이 있기 때문입니다.
I-- 작전 자체는 CPSR (현재 프로그램 상태 레지스터)에 영향을 미칩니다. CPSR의 공통 플래그는 N (결과는 음수), z (결과는 0), C (캐리) 및 O (오버플로)입니다. i> 0은 z 플래그로 직접 판단 할 수 있습니다.
I ++ 작동은 CPSR (현재 프로그램 상태 레지스터)에도 영향을 미치지 만 O (오버플로) 플래그에만 영향을 미치며 I <n의 판단에 도움이되지 않습니다. 따라서 추가 비교 명령이 필요하므로 각 루프마다 하나의 명령을 실행해야합니다.
간단히 말해서 0에 비해 지시가 적을 것입니다. 따라서 고급, 대기 및 고급 I- 재활용.
2 회원 변수 대 국부 변수
JDK 소스 코드는 거의 모든 방법에서 멤버 변수를 수락하기 위해 로컬 변수를 거의 사용합니다.
public int compareto (String anotherstring) {int len1 = value.length; int len2 = anotherstring.value.length;로컬 변수는 메소드의 스레드 스택에서 초기화되기 때문에 멤버 변수는 힙 메모리에서 초기화되므로 전자는 더 빠르기 때문에 메소드에서 직접 멤버 변수를 사용하지 않고 로컬 변수를 사용하지 않으려 고합니다.
3 의도적으로 레지스터에로드 && 잠금 장치 외부에 시간이 많이 걸리는 작업을 넣으십시오.
ConsurenThashMap에서는 잠금 세그먼트의 작동이 매우 흥미 롭습니다. 직접 잠금 장치는 아니지만 스핀 잠금 장치와 유사합니다. 반복적으로 자물쇠를 얻으려고합니다. 잠금을 획득하는 과정에서 링크 된 목록을 통과하여 데이터가 먼저 레지스터 캐시에로드되어 잠금 프로세스의 편의를 피할 수 있습니다. 동시에, 새 개체를 생성하는 작업은 잠금 장치에서 시간이 많이 걸리는 작업을 피하기 위해 잠금 장치 외부에 배치됩니다.
Final v put (k key, int hash, v value, boolean onlyifabsent) { /**이 세그먼트에 글을 쓰기 전에 먼저 세그먼트의 독점 잠금을 얻어야합니다. Lock ()을 강제하는 것이 아니라*/ hashentry <k, v> node = trylock ()을 시도하는 것입니다. NULL : ScanAndLockForput (키, 해시, 값); scanandlockforput () 소스 코드
Private Hashentry <k, v> scanandlockforput (k key, int hash, v value) {hashentry <k, v> first = entherforhash (this, hash); Hashentry <k, v> e = 첫 번째; Hashentry <k, v> node = null; int retries = -1; // 노드를 찾는 동안 음수 // 잠금을 얻기 위해 루핑 (! trylock ()) {hashentry <k, v> f; // if (retries <0) {if (e == null) {if (node == null) // node를 구체적으로 생성 // 값이없고 새 개체를 생성 할 필요가 없으며 새 node = new Hashentry <k, v> (hash, values, values, null)를 생성 할 필요가 없습니다. 재시도 = 0; } // 해시 위치 키는 동일하며 (key.equals (e.key)) Restries = 0; else // 다시 리트리는 링크 된 목록을 캐시 e = e.next로 자동 읽을 수 있습니다. } // 다시 시작하면> 0이면 스핀 잠금 장치가됩니다. 물론, 검색 수가 max_scan_retries (단일 코어 1 멀티 코어 64)를 초과하는 경우, 그것을 잡아 당기지 말고 차단 대기열을 입력하고 잠금을 기다리는 것을 기다립니다 // 잠금 ()은 잠금을 얻은 후 돌아올 때까지 차단 방법입니다. 부서지다; } else if ((Retries & 1) == 0 && // 현재 큰 문제가 있습니다. // 항목이 변경된 경우 재 트로버를 다시 트로버트 = -1; }} 반환 노드;} 4 먼저 사용하여 객체 평등을 결정할 수 있습니다 ==
객체의 동일 여부를 판단 할 때 == 먼저, == 주소를 직접 비교할 수 있기 때문에, 매우 빠른 주소를 직접 비교하고, Equals는 가장 많은 객체 값을 비교할 수 있습니다. 따라서 가능하면 A == B ||를 사용할 수 있습니다 a.equals (b) 물체가 동일한지 비교합니다.
5 과도 정보
과도는 직렬화를 방지하는 데 사용되지만 해시 맵 소스 코드의 내부 배열은 과도로 정의됩니다.
/*** 테이블, 필요에 따라 크기가 조정되었습니다. 길이는 항상 2의 힘이어야합니다. */ 과도 항목 <k, v> [] table = (Entry <k, v> []) empty_table;
그러면 내부의 키 값 쌍이 직렬화 될 수 없습니까? 네트워크에서 HashMap을 사용하여 전송하는 것이 불가능하지 않습니까? 사실, 그렇지 않습니다.
효과적인 Java 2nd, Item75, Joshua는 다음을 언급했습니다.
예를 들어 해시 테이블의 경우를 고려하십시오. 물리적
표현은 키 값을 포함하는 해시 버킷 순서입니다
항목. 항목이있는 버킷은 해시의 함수입니다.
일반적으로 동일하지 않은 키 코드
JVM 구현에서 JVM 구현까지. 사실, 그것은조차도 아닙니다
달리기부터 달리기까지 동일하게 보장됩니다. 그러므로 수락
해시 테이블의 기본 직렬화 된 양식은 심각한 것으로 구성됩니다.
벌레. 해시 테이블의 직렬화 및 사형화는 AN을 산출 할 수 있습니다
불변이 심각하게 손상된 대상.
이해하는 방법? hashmap.get ()/put ()을보고 읽기 및 쓰기 맵이 Object.hashCode ()를 기반으로한다는 것을 알기 위해 읽고 쓸 수있는 버킷을 결정하십시오. Object.hashCode ()는 기본 메소드이며 JVMS에서 다를 수 있습니다.
예를 들어, 입력을 해시 맵에 저장하면 키는 문자열 "문자열"입니다. 첫 번째 Java 프로그램에서 "String"의 hashcode ()는 1이고 버킷 번호 1은 저장됩니다. 두 번째 Java 프로그램에서 "String"의 hashcode ()는 2 일 수 있고 버킷 번호 2는 저장됩니다. 기본 직렬화가 사용되는 경우 (Entry [] 테이블에 과도가 필요하지 않음),이 해시 맵 후 첫 번째 Java 프로그램의 직렬화를 통해 두 번째 Java 프로그램을 가져 오면 메모리 분포가 동일합니다.
예를 들어, 첫 번째 Java 프로그램에서 "Fang Laosi"의 hashcode ()는 1이고 표 [1]의 키 값 쌍 항목을 Hashmap, key = "Fang Laosi"에 저장하면 저장됩니다. 자, 이제 다른 JVM 프로그램으로 전달됩니다. "Fang Laosi"의 hashcode ()는 2 일 수 있으므로 표 [2]로 이동하여 결과가 존재하지 않습니다.
Hashmap의 현재 readobject 및 writeObject는 컨텐츠를 출력/입력하고 해시 맵을 재생하는 데 사용됩니다.
6 숯을 사용하지 마십시오
Char는 Java에서 UTF-16에서 인코딩되며 2 바이트이며 2 바이트는 모든 문자를 나타낼 수 없습니다. 2 바이트를 BMP라고하고, 다른 바이트는 높은 대리 및 낮은 대리라고하며, 스크라이브로 표시되는 4 바이트 문자를 형성합니다. 예를 들어 문자열 소스 코드의 indexof :
// 여기에 공개 int indexof (int ch, int fromIndex)의 판단을 용이하게하기 위해 숯을 수락하는 int {final int max = value.length; if (fromindex <0) {Fromindex = 0; } else if (fromindex> = max) {// 참고 : index가 -1 >>> 근처에있을 수 있습니다. 반품 -1; } // bmp 범위에서 (ch <arribute.min_supplementary_code_point) {// 대부분의 경우를 다루고 있습니다 (ch는 bmp 코드 포인트 또는 a negative value (invalid code point)) 최종 char [] value = this.value; for (int i = fromIndex; i <max; i ++) {if (value [i] == ch) {return i; }} 반환 -1; } else {// 그렇지 않으면 4 바이트 판단 방법으로 이동하십시오. return indexofSupplementary (ch, fromIndex); }}따라서 Java의 Char는 UTF16의 BMP 부분 문자 만 나타낼 수 있습니다. CJK (중국, 일본 및 한국 통합 표판)의 경우 부분 확장 문자 세트를 표현할 수 없습니다.
예를 들어, 아래 그림의 Ext-A 부분을 제외하고 Char는 표현할 수 없습니다.
또한 Char를 사용해야한다는 또 다른 말이 있습니다. 비밀번호에 문자열을 사용하지 마십시오. 문자열은 상수이며 (즉, 창조 후에는 변경할 수 없음) 상수 수영장에 저장됩니다. 다른 프로세스가 프로세스의 메모리를 덤프 할 수 있다면, 상수 풀이 덤프 될 때 암호가 유출되고, Char []는 다른 정보를 변경할 수 있으므로 암호 누출 위험이 줄어 듭니다.
그러나 나는 개인적으로 당신이 기억을 덤프 할 수 있다고 생각합니다. 숯이 그것을 막을 수 있습니까? 상수 수영장에서 문자열이 재활용되지 않고 다른 스레드에 의해 상수 수영장에서 직접 읽지 않는 한, 아마도 매우 드 rare니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.