Na verdade, há pouquíssimas razões para se trocar o ArrayList pelo vector. Note que o código sincronizado que ele gerou na parte de baixo:
synchronized (list) {
list.clear();
list.add(?888″);
list.remove(0);
}
Seria seguro mesmo para um ArrayList. Desde que em todos os trechos onde fosse usado houvessem sincronizações desse tipo.
O importante é entender os tipos de thread-safety. Uma classe pode ser:
Imutável: Então, ela aparece como constante para os clientes. Nesse caso, não há necessidade de sincronização, mas ainda sim há thread-safety;
Thread-safe: Tem todos os seus métodos sincronizados. Então, chamadas sequenciais aos seus métodos por diversas threads não tornam o seu estado inválido. Isso não significa que as chamadas “entre” os métodos seja segura. Mas só que a classe, por si só, não permitirá que uma thread corrompa seu estado. Exemplos: Classe java.util.Timer
Thread-safe condicional: Igual a acima, mas existe uma ordem específica que os métodos devam ser chamados para que a classe se torne thread-safe. Para eliminar a possibilidade de interferência, o cliente deveria requisitar um lock antes de iniciar suas operações. Um exemplo disso é a classe Vector e HashTable.
Compatível com threads: A classe pode ser usada de maneira segura, desde que em todos os locais que seja chamada exista um código sincronizado. Um exemplo é, como expliquei ali em cima, o ArrayList. E, geralmente, é o que acontece no caso das listas.
Hostil com threads: A classe não pode ser usada em ambientes multi-thread, nem mesmo com a presença de sincronização em seus métodos. Geralmente ocorre com classes que dependem de recursos externos, não sincronizados. Ou classes que acessem singletons não thread-safe.