JavaRush /Blog Java /Random-ES /Traducción: Las 50 preguntas principales de la entrevista...
KapChook
Nivel 19
Volga

Traducción: Las 50 preguntas principales de la entrevista por hilo. Parte 2.

Publicado en el grupo Random-ES
La segunda parte de la traducción del artículo original Respuestas a las 50 preguntas principales de la entrevista sobre subprocesos Java para programadores novatos y experimentados. Primera parte.
  1. ¿Cómo comprobar si un hilo mantiene un candado?

  2. No tenía idea de que se podía comprobar si un hilo estaba actualmente bloqueado hasta que me encontré con esta pregunta en una entrevista telefónica. java.lang.Thread tiene un métodoholdLock(), devuelve verdadero si y sólo si el hilo actual mantiene el monitor en un objeto específico.
  3. ¿Cómo obtener un volcado de hilo?

  4. Un volcado de subprocesos le permite saber qué está haciendo un subproceso actualmente. Hay varias formas de obtener un volcado de subprocesos, según el sistema operativo. En Windows puedes usar la combinación Ctrl + Break, en Linux puedes usar el comando Kill -3. También puede utilizar la utilidad jstack; opera con la identificación del proceso, que puede averiguar utilizando otra utilidad jps.
  5. ¿Qué parámetro JVM se utiliza para controlar el tamaño de la pila del hilo?

  6. Este es uno de los parámetros -Xss simples que se utilizan para controlar el tamaño de la pila de un subproceso en Java.
  7. ¿Diferencias entre sincronizado y ReentrantLock?

  8. Hubo momentos en que la única forma de lograr la exclusión mutua era mediante la palabra clave sincronizada, pero tiene varias desventajas, como no poder extender el bloqueo más allá de un método o bloque de código, etc. Java 5 resuelve este problema proporcionando un control más granular a través de la interfaz Lock. ReentrantLock es una implementación de Lock común que proporciona un Lock con el mismo comportamiento básico y semántica que un monitor implícito, logrado mediante métodos sincronizados, pero con capacidades mejoradas.
  9. ¿Dados 3 hilos T1, T2 y T3? ¿Cómo implementar la secuencia T1, T2, T3?

  10. La coherencia se puede lograr de muchas maneras, pero simplemente puede usar el método join() para iniciar un hilo cuando otro haya terminado de ejecutarse. Para implementar la secuencia dada, primero debe iniciar el último hilo y luego llamar al método join() en orden inverso, es decir, T3 llama a T2.join y T2 llama a T1.join, por lo que T1 terminará primero y T3 al final. .
  11. ¿Qué hace el método del rendimiento?

  12. El método de rendimiento es una forma de pedirle a un subproceso que ceda CPU para que otro subproceso pueda ejecutarse. Este es un método estático y solo garantiza que el subproceso actual cederá el procesador, pero no decide a qué subproceso se ejecutará.
  13. ¿Cuál es el nivel de concurrencia de ConcurrentHashMap?

  14. ConcurrentHashMap logra su escalabilidad y seguridad de subprocesos al dividir el mapa real en secciones. Esta separación se logra mediante el uso de un nivel de paralelismo. Este es un parámetro opcional para el constructor ConcurrentHashMap y su valor predeterminado es 16.
  15. ¿Qué es el semáforo?

  16. Semaphore es un nuevo tipo de sincronizador. Este es un semáforo con contador. Conceptualmente, un semáforo controla un conjunto de permisos. Cada adquisición() bloquea, si es necesario, antes de que el permiso esté disponible y luego lo adquiere. Cada lanzamiento() agrega un permiso, lo que potencialmente libera al adquirente bloqueador. Sin embargo, esto no utiliza objetos de permiso reales; Semaphore simplemente almacena la cantidad de disponibles y actúa en consecuencia. Semaphore se utiliza para proteger recursos costosos que están disponibles en cantidades limitadas, como una conexión a una base de datos agrupada.
  17. ¿Qué sucede si la cola del grupo de subprocesos ya está llena y envía una tarea?

  18. Si la cola del grupo de subprocesos está llena, la tarea enviada será "rechazada". El método submit() de ThreadPoolExecutor genera una excepción RejectedExecutionException, después de lo cual se llama a RejectedExecutionHandler.
  19. ¿Diferencias entre los métodos de envío () y ejecución () en un grupo de subprocesos?

  20. Ambos métodos son formas de enviar una tarea a un grupo de subprocesos, pero existe una ligera diferencia entre ellos. Ejecutar (comando ejecutable) se define en la interfaz del Ejecutor y ejecuta la tarea dada en el futuro, pero lo más importante es que no devuelve nada. Por otro lado, enviar() es un método sobrecargado, puede aceptar tareas Ejecutables y Llamables y puede devolver un objeto Futuro que puede usarse para cancelar la ejecución y/o esperar el resultado de un cálculo. Este método se define en la interfaz ExecutorService, que hereda de la interfaz Executor, y cada clase de grupo de subprocesos, como ThreadPoolExecutor o ScheduledThreadPoolExecutor, hereda estos métodos.
  21. ¿Qué es un método de bloqueo?

  22. Un método de bloqueo es un método que bloquea hasta que se completa la tarea; por ejemplo, el método ServerSocket Accept() se bloquea mientras espera que el cliente se conecte. Aquí, bloquear significa que el control no volverá al método de llamada hasta que se complete el trabajo. Por otro lado, existen métodos asincrónicos o sin bloqueo que se completan antes de que se complete la tarea.
  23. ¿Es seguro el hilo Swing?

  24. En pocas palabras, no, Swing no es seguro para subprocesos, pero debes explicar lo que quieres decir con eso, incluso si el entrevistador no pregunta. Cuando decimos que Swing no es seguro para subprocesos, generalmente nos referimos al hecho de que es un componente que no puede ser modificado por múltiples subprocesos. Todos los cambios en los componentes de la GUI deben realizarse en el subproceso AWT, y Swing proporciona métodos sincrónicos y asincrónicos para programar dichos cambios.
  25. ¿Diferencias entre invokeAndWait e invokeLater?

  26. Estos son dos métodos de Swing API que permiten a los desarrolladores actualizar los componentes de la GUI desde subprocesos en lugar de desde el subproceso de Event Manager. InvokeAndWait() actualiza sincrónicamente un componente de la GUI, como una barra de progreso; cada vez que se realiza progreso, la barra debe actualizarse para reflejar los cambios. Si se realiza un seguimiento del progreso en otro hilo, debe llamar a invokeAndWait() para asignar el hilo del Distribuidor de eventos para actualizar ese componente. E invokeLater() es una llamada asincrónica para actualizar componentes.
  27. ¿Qué métodos de Swing API son seguros para subprocesos?

  28. Esta pregunta es nuevamente sobre Swing y la seguridad de subprocesos, aunque los componentes de Swing no son seguros para subprocesos, existen métodos que se pueden llamar de manera segura desde múltiples subprocesos. Sé que repaint() y revalidate() son seguros para subprocesos, pero existen otros métodos en diferentes componentes Swing, como los métodos setText() de JTextComponent y insert() y append() de JTextArea.
  29. ¿Cómo crear objetos inmutables?

  30. Puede parecer que esta pregunta no tiene nada que ver con los subprocesos múltiples y la concurrencia, pero sí la tiene. La inmutabilidad ayuda a simplificar el código paralelo ya complejo. Un objeto inmutable es muy costoso para los desarrolladores porque puede propagarse sin ningún tipo de sincronización. Desafortunadamente, Java no tiene la anotación @Immutable, lo que hará que su objeto sea inmutable, por lo que los desarrolladores deben trabajar duro. Para crear un objeto inmutable, debe seguir los conceptos básicos: inicialización en el constructor, sin definidores, sin fuga de referencias, almacenamiento de copias separadas de objetos mutables.
  31. ¿Qué es ReadWriteLock?

  32. En general, ReadWriteLock es el resultado de una técnica de análisis de bloqueos para mejorar el rendimiento de aplicaciones paralelas. Esta es una interfaz que se agregó en Java 5. Opera con un par de bloqueos relacionados, uno para operaciones de lectura y otro para operaciones de escritura. Un bloqueo de lector puede ser mantenido simultáneamente por varios hilos de lectura hasta que no queden escritores. El candado de escritura es exclusivo. Si lo desea, puede implementar una interfaz con su conjunto de reglas o puede usar ReentrantReadWriteLock, que admite un máximo de 65535 bloqueos de escritura recursivos y 65535 bloqueos de lectura.
  33. ¿Qué es el giro ocupado?

  34. Busy Spin es una técnica que utilizan los programadores para forzar a un hilo a esperar bajo una determinada condición. A diferencia de los métodos tradicionales, esperar(), dormir() o producir(), que implican ceder el control del procesador, este método no cede el procesador; en cambio, simplemente ejecuta un bucle vacío. ¿Por qué alguien haría esto? Para guardar el caché del procesador. En sistemas multinúcleo, es posible que un subproceso suspendido continúe ejecutándose en otro núcleo, lo que significa una reconstrucción de la caché. Para evitar costosas reconstrucciones, el programador prefiere esperar menos utilizando el giro ocupado.
  35. ¿Diferencias entre variables volátiles y atómicas?

  36. Ésta es una pregunta bastante interesante; al principio, las variables volátiles y atómicas parecen muy similares, pero siguen siendo diferentes. Una variable volátil proporciona una garantía de que ocurrirá antes de que se produzca una escritura antes de cualquier escritura posterior; no garantiza la atomicidad. Por ejemplo, la operación count++ no se volverá atómica simplemente porque el recuento se declare volátil. Por otro lado, la clase AtomicInteger proporciona un método atómico para realizar operaciones tan complejas de forma atómica; por ejemplo, getAndIncrement() es un reemplazo atómico del operador de incremento y se puede utilizar para incrementar atómicamente el valor actual en uno. También existen versiones atómicas para otros tipos de datos.
  37. ¿Qué sucede si un hilo arroja una excepción en un bloque sincronizado?

  38. Esta es otra pregunta capciosa para los programadores habituales de Java. No importa cómo salga de un bloque sincronizado, ya sea normalmente finalizando la ejecución o lanzando repentinamente una excepción, el subproceso libera el bloqueo adquirido cuando ingresa al bloque sincronizado. Esta es una de las razones por las que prefiero un bloque de bloqueo sincronizado a una interfaz que requiere especial cuidado al liberar el bloqueo, lo que generalmente se logra liberando el bloqueo en un bloque finalmente.
  39. ¿Qué es el bloqueo de doble verificación de Singleton?

  40. Esta es una de las preguntas de entrevista más populares y, sin embargo, a pesar de su popularidad, las posibilidades de que un candidato la responda son, en el mejor de los casos, del 50%. La mitad de las veces fallan al escribir el código y la otra mitad al explicar cómo se rompió y solucionó en Java 1.5. Esta es una forma antigua de crear un singleton seguro para subprocesos que intenta optimizar el rendimiento bloqueando solo cuando se crea una instancia de la instancia singleton por primera vez, pero debido a la complejidad y al hecho de que se rompió en JDK 1.4, personalmente no me gusta él. Aún así, incluso si no prefieres este enfoque, es útil conocerlo desde la perspectiva de la entrevista.
  41. ¿Cómo crear un Singleton seguro para subprocesos?

  42. Esta pregunta complementa la anterior. Si dice que no le gusta el bloqueo de doble verificación, el entrevistador se verá obligado a preguntar sobre formas alternativas de crear un Singleton seguro para subprocesos. Y lo son, puede aprovechar las funciones de carga de clases e inicialización de variables estáticas para crear una instancia de Singleton, o puede aprovechar el potente tipo de enumeración.
  43. ¿Enumera 3 costumbres que sigues en la programación paralela?

  44. Esta es mi pregunta favorita porque creo que hay ciertas reglas que se deben seguir al escribir código paralelo, lo que ayuda con el rendimiento, la depuración y el soporte. A continuación se muestran las 3 mejores reglas que creo que todo programador de Java debería seguir:
    • Siempre da nombres significativos a tus hilos.
    • Encontrar un error o rastrear una excepción en el código paralelo es una tarea bastante difícil. OrderProcessor, QuoteProcessor o TradeProcessor es mucho mejor que Thread-1. Hilo-2 y Hilo-3. El nombre debe reflejar la tarea realizada por el hilo. Todos los marcos principales e incluso JDK siguen esta regla.
    • Evite bloquear o reducir el alcance de la sincronización
    • El bloqueo es costoso y el cambio de contexto es aún más costoso. Intenta evitar la sincronización y el bloqueo en la medida de lo posible y reducirás la sección crítica al mínimo requerido. Es por eso que prefiero un bloqueo cronometrado a un método cronometrado porque le brinda control absoluto sobre el alcance del bloqueo.
    • Entre sincronizadores y esperar y notificar, elija sincronizadores
    • En primer lugar, sincronizadores como CountDownLatch, Semaphore, CyclicBarrier o Exchanger simplifican la codificación. Es muy difícil implementar un flujo de control complejo usando esperar y notificar. En segundo lugar, estas clases son escritas y mantenidas por los mejores en el negocio y existe una buena posibilidad de que sean optimizadas o reemplazadas con un mejor código en futuras versiones de JDK. Al utilizar utilidades de sincronización de alto nivel, obtendrá automáticamente todos estos beneficios.
    • Entre Colección Concurrente y Colección Sincronizada, elija Colección Concurrente
    • Esta es otra regla simple que es fácil de seguir y obtener beneficios. Las colecciones concurrentes son más escalables que sus contrapartes sincronizadas, por lo que es mejor usarlas al escribir código paralelo. Entonces, la próxima vez que necesite un mapa, piense en ConcurrentHashMap antes de pensar en Hashtable.
  45. ¿Cómo forzar el inicio de un hilo?

  46. Esta es una pregunta similar a cómo forzar la ejecución de la recolección de basura. En resumen, de ninguna manera, por supuesto puedes hacer una consulta usando System.gc(), pero no garantiza nada. No hay absolutamente ninguna forma de forzar el inicio de un subproceso en Java, esto está controlado por el programador de subprocesos y Java no proporciona ninguna API para controlarlo. Esta parte de Java sigue siendo aleatoria.
  47. ¿Qué es el marco Fork/Join?

  48. El marco Fork/Join introducido en JDK 7 es una poderosa utilidad que permite al desarrollador aprovechar los múltiples procesadores de los servidores modernos. Está diseñado para trabajos que pueden descomponerse recursivamente en pequeñas partículas. El objetivo es utilizar toda la potencia informática disponible para aumentar el rendimiento de su aplicación. Una ventaja importante de este marco es que utiliza un algoritmo de robo de trabajo (de trabajo - trabajo y robo - a robar). Los subprocesos de trabajo que se han quedado sin trabajos pueden robar trabajos de otros subprocesos que todavía están ocupados.
  49. ¿Cuál es la diferencia entre llamadas a esperar() y dormir()?

  50. Aunque tanto esperar como dormir representan una especie de pausa en una aplicación Java, son dispositivos para necesidades diferentes. La espera se utiliza para la comunicación de subprocesos internos, se bloquea si la condición de espera es verdadera y espera la notificación si las acciones de otro subproceso hacen que la condición de espera sea falsa. Por otro lado, el método sleep() simplemente abandona el procesador o detiene la ejecución del hilo actual durante un período de tiempo específico. Llamar a sleep() no libera el bloqueo retenido por el hilo actual.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION