El título es el siguiente:
La clase pública testSync2 implementa runnable {int b = 100; sincronizado void m1 () lanza interruptedException {b = 1000; Thread.sleep (500); // 6 System.out.println ("b =" + b); } sincronizado void m2 () lanza interruptedException {thread.sleep (250); // 5 b = 2000; } public static void main (string [] args) lanza interruptedException {testSync2 tt = new testSync2 (); Hilo t = nuevo hilo (tt); // 1 t.start (); // 2 tt.m2 (); // 3 System.out.println ("Hilo principal b =" + tt.b); // 4} @Override public void run () {try {m1 (); } catch (InterruptedException e) {E.PrintStackTrace (); }}}El resultado de salida de este programa?
Resultados de la salida del programa
Hilo principal B = 2000b = 1000
o
hilo principal B = 1000B = 1000
Verifique los puntos de conocimiento
En Java, los programas de múltiples subprocesos son los más difíciles de entender y depurar. Muchas veces los resultados de la ejecución no se ejecutan como lo imaginamos. Por lo tanto, es muy difícil de leer múltiples en Java. Recuerdo vagamente cuando estaba tomando el nivel 2 del idioma C en la universidad, cuál es la pregunta en ++ y muchos otros niveles de prioridad coinciden con los resultados finales de salida. Quiero tomar algunas preguntas de prioridad y combinación de corredores para este tipo de pregunta. Simplemente recíalo respaldándolo, pero Java Multi-Threading todavía necesita ser bien entendido, el respaldo no se puede hacer.
Comencemos un breve análisis:
Esta pregunta implica 2 hilos (hilo principal principal, hilo infantil), y las palabras clave implican sincronizados y hilos.
La palabra clave sincronizada sigue siendo bastante complicada (a veces no lo entiendo bien, por lo que la pregunta anterior tiene algunos malentendidos). Su función es realizar la sincronización de subprocesos (hay muchos métodos para implementar la sincronización de hilos, es solo una especie de otras cosas de las que hablarán los artículos de seguimiento. Algunas implementaciones del maestro Doug Lea deben estudiarse cuidadosamente). Su trabajo es bloquear el código que necesita sincronización, para que solo un hilo pueda ingresar el bloque de sincronización a la vez (de hecho, es una estrategia pesimista) para garantizar que el hilo solo recuerde la seguridad.
El uso de la palabra clave general sincronizada
En el código anterior, el uso de sincronizado en realidad pertenece al segundo caso. Actuando directamente sobre el método de instancia: es equivalente a bloquear la instancia actual. Antes de ingresar el código de sincronización, debe obtener el bloqueo de la instancia actual.
Posibles malentendidos
1. Dado que no entendemos sincronizado, muchas veces, operamos un método sincronizado mediante múltiples subprocesos. Cuando dos hilos llaman 2 métodos sincronizados diferentes, se cree que es irrelevante. Esta idea es el malentendido. Actuando directamente sobre el método de instancia: es equivalente a bloquear la instancia actual. Antes de ingresar el código de sincronización, debe obtener el bloqueo de la instancia actual.
2. Si se llama a un método sincronizado. Otra llamada a un método normal no tiene nada que hacer, y los dos no tienen una relación de espera.
Estos son muy útiles para el análisis posterior.
Thread.sleep
Safess el hilo actual (es decir, el hilo que llama al método) por un período de tiempo, dando a otros hilos la oportunidad de continuar la ejecución, pero no libera el bloqueo del objeto. Es decir, si la sincronización sincronizada es rápida, otros hilos aún no pueden acceder a datos compartidos. Tenga en cuenta que este método necesita capturar excepciones, lo cual es muy útil para el análisis posterior.
Proceso de análisis
Java se ejecuta a partir del método principal. Se dice que hay 2 hilos, pero incluso si modifica la prioridad del hilo aquí, es inútil. La prioridad es solo cuando los dos programas aún no se han ejecutado. Ahora, una vez que se ejecuta este código, el hilo principal se ha ejecutado. Para la variable de atributo int b = 100, no habrá un problema de visibilidad porque se usa sincronizado (y no es necesario decir que la declaración volátil se usa), al realizar el paso 1 (hilo t = nuevo hilo (tt); // 1) El hilo está en nuevo estado y aún no ha comenzado a funcionar. Cuando se ejecutan los 2 pasos (t.start (); // 2) Cuando se llama el método de inicio, el hilo realmente se inicia y ingresa al estado ejecutable. El estado ejecutable significa que se puede ejecutar y todo está listo, pero no significa que deba ejecutarse en la CPU. Si hay una ejecución real depende de la programación de la CPU del servicio. Aquí, al realizar los 3 pasos, primero debe obtener el bloqueo (porque el inicio debe llamar al método nativo, y todo está listo después de completar el uso, pero no significa que se ejecute en la CPU. Si hay una ejecución real depende de la programación de la CPU del servicio, y luego se debe llamar al método de ejecución y se ejecutará el método M1). De hecho, no importa si el hilo. Cuando se ejecutan los 3 pasos, el hilo infantil está realmente listo pronto, pero debido a que sincronizado existe y actúa como el mismo objeto, el hilo infantil tiene que esperar. Dado que la orden de ejecución en el método principal se ejecuta secuencialmente, debe completarse después de ejecutar el paso 3 antes de alcanzar el cuarto paso. Dado que se completa la ejecución del paso 3, el hilo infantil puede ejecutar M1. Aquí hay un problema que obtiene primero el subproceso múltiple. Si primero se obtienen los 4 pasos, entonces el hilo principal B = 2000. Si se obtiene el hilo infantil M1, B puede haberse asignado a 1000 o antes de que se asignen los 4 pasos, el resultado posible es el hilo principal B = 1000 o el hilo principal B = 2000. Si los 6 pasos se eliminan aquí, entonces b = ejecutar antes y el hilo principal b = antes es incierto. Sin embargo, dado que existen 6 pasos, pase lo que pase, el hilo principal B = está al frente, por lo que depende de la situación si es igual a 1000 o 2000. Después de eso, B = 1000 definitivamente es fijo.
Algunas sugerencias para múltiples subprocesos
También hay algunos consejos para compartir en los artículos posteriores. El subproceso múltiple es particularmente importante y difícil. Espero que todos pasen más tiempo en ello.
Algunas técnicas de depuración para múltiples lecturas
Debido a los puntos de interrupción, todos los hilos deben detenerse al pasar a través de los puntos de interrupción, lo que hace que este punto se interrumpa constantemente, lo cual es muy incómodo. Hay puntos de interrupción condicionales en Eclispe, y puede detenerse cuando se cumplan las condiciones, por lo que esto es conveniente.
Resumir
Lo anterior es la pregunta de entrevista de Java más difícil en la historia que el editor le ha presentado. Espero que te sea útil. Si tiene alguna pregunta, déjame un mensaje y el editor le responderá a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!