Prefacio
Esto está bastante inactivo durante este período, así que miré el código fuente de JDK. Un ingeniero general de desarrollo senior puede mejorarse leyendo algún código fuente. Este artículo resume algunos "pequeños consejos" en el código fuente de JDK y los comparte para su referencia y aprendizaje. No diré mucho a continuación, echemos un vistazo a la introducción detallada juntos.
1 i ++ vs i--
Línea 985 del código fuente de cadena, en el método igual
while (n-! = 0) {if (v1 [i]! = v2 [i]) return false; i ++; }Este código se usa para juzgar si la cadena es igual, pero hay una cosa extraña que usa i-! = 0 para hacer juicios. ¿No usamos normalmente i ++? ¿Por qué usar yo ...? Y el número de ciclos es el mismo. La razón es que habrá una instrucción más después de la compilación:
Yo ... la operación en sí afectará CPSR (registro actual del estado del programa). Los indicadores comunes para CPSR son n (el resultado es negativo), z (el resultado es 0), C (transporte) y O (desbordamiento). i> 0, puede ser juzgado directamente por la bandera Z.
La operación I ++ también afectará a CPSR (registro actual del estado del programa), pero solo afectará el indicador O (con desbordamiento), lo que no ayudará en el juicio de i <n. Por lo tanto, se necesita una instrucción de comparación adicional, lo que significa que se debe ejecutar una instrucción más para cada bucle.
En pocas palabras, en comparación con 0, habrá una instrucción menos. Por lo tanto, recicla I--, de alta gama, atmosférica y de alta gama.
Variables de 2 miembros frente a variables locales
El código fuente JDK casi utiliza una variable local para aceptar variables miembros en cualquier método, por ejemplo
public int Compareto (String AnothString) {int Len1 = value.length; int len2 = anotherstring.value.length;Debido a que las variables locales se inicializan en la pila de subprocesos del método, mientras que las variables miembros se inicializan en la memoria de almacenamiento intermedia, obviamente la primera es más rápida, por lo que intentamos evitar usar variables miembros directamente en el método, pero en su lugar usamos variables locales.
3 Cargando deliberadamente en registros && Poner operaciones que consumen mucho tiempo fuera del bloqueo
En concurrenthashmap, la operación del segmento de bloqueo es muy interesante. No es un bloqueo directo, pero es similar a un bloqueo de spinning. Repetidamente trata de adquirir la cerradura. Durante el proceso de adquisición del bloqueo, atravesará la lista vinculada, de modo que los datos se cargarán primero en la memoria caché de registro, evitando la conveniencia en el proceso de bloqueo. Al mismo tiempo, la operación de generar nuevos objetos también se coloca fuera del bloqueo para evitar operaciones que requieren mucho tiempo en el bloqueo
Final v put (k key, int hash, valor v, boolean solyifabsent) { /** Antes de escribir en este segmento, debe obtener primero el bloqueo exclusivo del segmento. No es forzar bloqueo (), sino probar*/ hashentry <k, v> node = trylock ()? NULL: ScanandlockFORPUT (clave, hash, valor); Código de origen ScanandLockFORPut ()
Hashentry privado <k, v> scanandlockforcut (k key, int hash, valor v) {hashentry <k, v> first = EntryforHash (this, hash); Hashentry <k, v> e = primero; Hashentry <k, v> nodo = null; int reintentos = -1; // negativo al localizar el nodo // bucle para bloquear mientras (! trylock ()) {Hashentry <k, v> f; // para volver a verificar primero a continuación if (reintenta <0) {if (e == null) {if (node == null) // especulativamente crea nodo // El bit hash no tiene valor, crea un objeto nuevo y no es necesario que vaya al bloqueo del método put () para crear un nuevo nodo = new Hashentry <k, v> (ha>, clave, valor, valor, valor, valor); reintentos = 0; } // La tecla de posición hash es la misma, degenerando en un bloqueo de giro más si (key.equals (E.Key)) reintentos = 0; else // Los reintentos pueden leer automáticamente la lista vinculada en el caché e = e.next; } // Cuando se vuelve> 0, se convierte en un bloqueo de spinning. Por supuesto, si el número de reintentos excede a Max_Scan_retries (Single Core 1 Multi-n-n-n-n-n-n-core 64), no logra, ingrese la cola de bloqueo y espere que el bloqueo // bloqueo () es el método de bloqueo hasta que regrese después de obtener el bloqueo, de lo contrario se cuelgará si (++ retries> max_scan_retries) {bloqueo ();; romper; } else if ((reintents & 1) == 0 && // Hay un gran problema en este momento, es decir, los nuevos elementos ingresan a la lista vinculada y se convierten en un nuevo encabezado //, por lo que la estrategia aquí es que es equivalente a pasar por el método ScanandlockFifutput nuevamente (F = Entryforhash (este, hash))! = Primero) {First = F; // volver a traver si la entrada cambió reintentos = -1; }} nodo de retorno;} 4 Puede usarlo primero para determinar la igualdad de objeto ==
Al juzgar si los objetos son iguales, puede usar == primero, porque == compare directamente las direcciones, que es muy rápida, mientras que iguales comparará la mayoría de los valores de objetos, que es relativamente lento. Entonces, si es posible, puede usar A == B || A.Equals (b) para comparar si los objetos son iguales.
5 sobre transitorio
Transitorio se usa para prevenir la serialización, pero la matriz interna en el código fuente de HashMap se define como transitorio.
/*** La tabla, redimensionada según sea necesario. La longitud siempre debe ser un poder de dos. */ entrada transitoria <k, v> [] table = (entrada <k, v> []) vacía_table;
Entonces, ¿no se pueden serializar los pares de valor clave en el interior? ¿No es imposible transmitir usando hashmap en la red? De hecho, no lo es.
Java 2do efectivo, item75, Joshua mencionó:
Por ejemplo, considere el caso de una tabla hash. Lo físico
La representación es una secuencia de cubos hash que contienen valor clave
entradas. El balde en el que reside una entrada es una función del hash
Código de su clave, que, en general, no se garantiza que es el mismo
Desde la implementación de JVM hasta la implementación JVM. De hecho, ni siquiera
Garantizado para ser lo mismo de correr a ejecución. Por lo tanto, aceptar el
El formulario serializado predeterminado para una tabla hash constituiría un
bicho. Serializar y deserializar la tabla hash podría producir un
Objeto cuyos invariantes eran seriamente corruptos.
¿Cómo entender? Eche un vistazo a hashmap.get ()/put () para saber que la lectura y la escritura del mapa se basan en object.hashcode () para determinar de qué balde leer/escribir. Object.HashCode () es un método nativo, que puede ser diferente en diferentes JVM.
Por ejemplo, guarde una entrada a hashmap, la clave es la cadena "cadena". En el primer programa Java, el hashcode () de "cadena" es 1, y el número 1 se almacena; En el segundo programa Java, el hashcode () de "String" puede ser 2, y se almacena el cubo número 2. Si se usa la serialización predeterminada (la tabla de entrada [] no requiere transitorio), luego de que este hashmap importa el segundo programa Java a través de la serialización del primer programa Java, su distribución de memoria es la misma, lo que está mal.
Por ejemplo, si guarda una entrada de par de valores clave a HashMap, Key = "Fang Laosi", en el primer programa Java, el hashcode () de "Fang Laosi" es 1, y la tabla [1] se almacena. Ok, ahora se pasa a otro programa JVM, el hashcode () de "Fang Laosi" puede ser 2, por lo que va a la mesa [2] para obtenerlo, y el resultado no existe.
El actual ReadObject y WriteObject de HashMap se utilizan para emitir/ingresar contenido y regenerar hashmap.
6 No uses Char
Char está codificado en UTF-16 en Java, y es 2 bytes, y 2 bytes no pueden representar a todos los personajes. Los 2 bytes se llaman BMP, y el otro se llama alto sustituto y bajo sustituto para formar un carácter de 4 bytes representado por escribas. Por ejemplo, indexOf en el código fuente de cadena:
// Aquí hay un int para aceptar un char para facilitar el juicio del rango público int indexOf (int ch, int fromindex) {final int max = value.length; if (fromIndex <0) {fromIndex = 0; } else if (fromIndex> = max) {// nota: fromindex podría estar cerca de -1 >>> 1. regreso -1; } // en el rango BMP if (ch <caracteres.min_supplementary_code_point) {// manejar la mayoría de los casos aquí (ch es un punto de código BMP o un valor negativo (punto de código no válido)) Final Che [] valor = this.value; for (int i = fromIndex; i <max; i ++) {if (valor [i] == ch) {return i; }} return -1; } else {// de lo contrario, vaya al método de juicio de cuatro bytes de retorno indexOfSupplementary (ch, fromIndex); }}Por lo tanto, el char de Java solo puede representar los caracteres parciales de BMP en UTF16. Para el ideograma unificado de CJK (China, Japón y Corea del Sur) conjuntos de carácter extendido parcial, no pueden expresarse.
Por ejemplo, Char no se puede representar, excepto la parte ext-a en la figura a continuación.
Además, hay otro dicho que debe usar Char. No use cadena para la contraseña. La cadena es una constante (es decir, no se puede cambiar después de la creación), y se guardará en el grupo constante. Si otros procesos pueden descargar la memoria del proceso, la contraseña se filtrará a medida que se arroje el grupo constante, y Char [] puede escribir otra información para cambiar, lo que significa que reducirá el riesgo de filtrar la contraseña.
Pero personalmente creo que puedes volcar la memoria. ¿Puede un char poder prevenirlo? A menos que la cadena no se recicle en la piscina constante y se lea directamente desde el grupo constante por otros hilos, probablemente sea muy raro.
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.