Il semble que tu ne maîtrise pas vraiment les outils de synchronisation, à voir ton code...
Tu as rendu la méthode run synchronized, à quoi bon? C'est la méthode principale du Thread, t'as pas prévu qu'un autre code que celui de la méthode start() du Thread puisse l'appeler? (d'ailleurs, pour commencer, est-ce que tu appelles cette méthode start?)
En plus derrière tu fais un synchronized(this), ce qui oblige le thread à réacquérir un verrou qu'il possède déjà (réentrance insensée), et tu as ensuite la méthode wait() qui lâche le verrou sur "this".
En fait tu dois toujours te poser la question suivante avant de mettre du code de synchronisation partout, quels objets sont partagés entre les threads et quels sont les dangers si quelqu'un les modifie? Ici, c'est clairement l'ArrayList qui est vulnérable.
La section critique de ton code c'est le parcours de la liste (le for). Or cette liste tu la passes par le constructeur, donc un autre objet que ton thread possède une référence externe sur l'arrayList, si il fait un add() ou un remove() pendant que le Thread exécute la boucle for(), dans le meilleur des cas tu auras une exception parce que l'itérateur est fail-fast, dans le pire des cas ça marchera et c'est ailleurs que ça pétera.
Même si je sais pas bien ce que tu essaies de faire, je te propose d'essayer avec une autre philosophie :
class Thread
{
private ArrayList cleanupList;
public void synchronized addConnectionToCleanupList(); //appelée de l'extérieur
public void run();
private void synchronized cleanupCurrentList(); //appelée par run le moment venu
}
Comme ça tu controles entièrement le réveil du thread de l'intérieur, moins de code spaghetti et c'est beaucoup plus sûr.