ソース見た。
エラーの原因は、サーバ側では送信のたびにObjectOutputStreamを作り直してるのに、クライアント側では同じObjectInputStreamを使い続けていることだ。
作り直すなら両方とも作り直す(この場合resetは要らない)、使い続けるなら両方とも使い続ける。混ぜてはいけない。

あと、現時点では大丈夫かもしれないが、潜在的な問題がある。
受信がブロックするのは当然なので別スレッドにするのは自然だけど、実は送信もブロックするから別スレッドにした方がいいんだ。
TCPには一定サイズのバッファがあって、相手側が読み出してくれなければ、バッファが一杯になった時点でそれ以上書き込めなくなり、ブロックする。
相手側が読み出してるつもりでも、例えば何かネットワークのトラブルでデータが届かなくなれば、同じようになる。
サーバ側で synchronized (this.recvMessageQueue) { } の中で sendClients 呼んでその中で writeObject してるけど、こういうロックを握ったままブロックする可能性があるのは非常によくない。
受信キューを握ったままブロックすると受信スレッドがみんな動けなくなるし、そうなるといずれクライアントの送信側もバッファが一杯になってみんな止まってしまう。

あとは、 clientSocketList が複数のスレッドから読み書きされてるから synchronized するべき。
いちいち synchronized するのが面倒なら元からスレッドセーフな CopyOnWriteArrayList を使うという手もある。
キューも LinkedBlockingQueue とか使えば synchronized する必要なくなる。 まぁこのへんはどっちでもいいけど。

ObjectIOストリームは、性能面では劣るけど、開発は楽だから、使いたければそれでいいんじゃない。
他の方法といっても、ファイルと一緒で、フォーマットを決めて読み書きするだけだよ。
いわゆるType-Length-Value的なやり方が普通だと思うけど、例えば文字列化して行単位で送るとか、XML形式で送るという方法もなくはない。
こういうのは性能やらメンテナンス性やら開発速度やらのトレードオフだから、好みの方法を使えばいいと思うよ。