Problemas de subprocesamiento/concurrencia son muy difíciles de replicar, que es una de las razones por las que debe diseñar para evitar o al menos minimizar las probabilidades. Esta es la razón por la cual los objetos inmutables son tan valiosos. Intente aislar objetos mutables en un solo hilo y luego controle cuidadosamente el intercambio de objetos mutables entre hilos. Intente programar con un diseño de entrega de objetos en lugar de objetos "compartidos". Para este último, utilice objetos de control totalmente sincronizados (que son más fáciles de razonar), y evite que un objeto sincronizado utilice otros objetos que también deben estar sincronizados, es decir, intente mantenerlos autónomos. Tu mejor defensa es un buen diseño.
Los bloqueos son los más fáciles de depurar, si puede obtener un seguimiento de pila cuando está bloqueado. Dada la traza, la mayoría de los cuales detectan interbloqueos, es fácil precisar el motivo y luego razonar sobre el motivo y cómo solucionarlo. Con interbloqueos, siempre va a ser un problema adquirir los mismos bloqueos en diferentes órdenes.
Los bloqueos en vivo son más difíciles de detectar, ya que observar el sistema mientras está en el estado de error es su mejor opción.
Las condiciones de carrera tienden a ser extremadamente difíciles de replicar, y son aún más difíciles de identificar a partir de la revisión manual del código. Con estos, el camino que suelo tomar, además de las extensas pruebas para replicar, es razonar sobre las posibilidades e intentar registrar información para probar o refutar teorías. Si tiene evidencia directa de corrupción estatal, es posible que pueda razonar sobre las posibles causas basadas en la corrupción.
Cuanto más complejo es el sistema, más difícil es encontrar errores de concurrencia y razonar sobre su comportamiento. Haga uso de herramientas como JVisualVM y los perfiles de conexión remota: pueden ser un salvavidas si puede conectarse a un sistema en estado de error e inspeccionar los hilos y objetos.
Además, tenga en cuenta las diferencias en el comportamiento posible que dependen de la cantidad de núcleos de CPU, tuberías, ancho de banda del bus, etc. Los cambios en el hardware pueden afectar su capacidad de replicar el problema. Algunos problemas solo se mostrarán en otros CPU de un solo núcleo solo en núcleos múltiples.
Una última cosa, intente utilizar objetos de concurrencia distribuidos con las bibliotecas del sistema - por ejemplo, en Java java.util.concurrent
es su amigo. Escribir sus propios objetos de control de concurrencia es difícil y plagado de peligros; déjalo en manos de los expertos, si tienes opción.
Hay herramientas que pueden detectar condiciones de carrera. Para .NET, puede echar un vistazo a [CHESS] (http://research.microsoft.com/en-us/projects/chess/) de Microsoft, que intenta detectar las condiciones de carrera ejecutando el código para cada intercalado posible. Para Java, puede obtener [ThreadSafe] (http://www.contemplateltd.com/threadsafe) que es una herramienta específica para detectar y corregir errores de simultaneidad. –
FindBugs es también una buena herramienta de análisis estático para encontrar posibles errores de subprocesamiento. –