Alcune cose:
a) Hai usato tue classi come ConnessioneSocket e Comunicazione, che non hai postato e quindi non sappiamo cosa fanno di preciso (sì, beh, più o meno si intuisce comunque).

b) Vedo "troppi" campi "di classe", ovvero static e questo personalmente non mi piace, perché in genere vuol dire che non stai usando bene gli oggetti incapsulando appropriatamente le cose.

c) Da quanto vedo, uno stesso Socket viene usato da più thread e questa non mi pare una bella cosa.

d) Vedo cose del tipo:
comunicazione.ricezioneBloccoDati(socket);

Anche qui dal punto di vista del design fa un po' "acqua". Non è bello passare un socket a qualcosa per leggere dei dati. Dovrebbe essere il contrario: un oggetto che ha il Socket (e prende/usa i suoi stream) e offre magari metodi per leggere qualcosa.

e) Ci sono comunque problemi di sincronizzazione: un wait/notify/notifyAll va invocato solo su un oggetto di cui il thread corrente possiede il lock. Se il thread A invoca xyz.wait(), allora il thread A deve possedere il lock dell'oggetto referenziato da xyz. La regola è questa e non può essere disattesa.

Nel run() del Runnable c'è un notify() che è invocato sul this ovvero appunto sulla istanza del Runnable. Non so a cosa ti serva, visto che non vedo un corrispettivo wait() sempre su quella stessa istanza del Runnable. E comunque in quel punto del notify() il thread non possiede certo il lock (non vedo nulla a riguardo) sul this. Quindi lì sicuramente fallisce.


Insomma .... manca parecchio, anche a livello concettuale.