Precisa de sincronização de prova de ArrayList em um ambiente multi-threaded
Eu estive nisso por uma semana agora fazendo minha pesquisa sobre como sincronizar corretamente uma ArrayList.
Minha principal questão em poucas palavras é que eu tenho uma ArrayList "master" de objetos. Threads diferentes podem entrar e adicionar / definir / remover desta lista. Eu preciso ter certeza de que quando um thread está interagindo com o ArrayList, outro não está mudando isso.
Agora eu li muitos artigos sobre a "melhor" maneira de lidar com isso:
use collections.synchronizedlistuse CopyOnWriteArrayListuse blocos synchronized () em conjunto com collections.synchronizedlistusar Vector (muitas pessoas são contra isso)Usando blocos sincronizados em cada iteração, adicionar / definir / remover bloco parece ser o que eu quero, mas as pessoas disseram que há muita sobrecarga.
Então eu comecei a brincar com CopyOnWriteArrayList (eu faço muito mais leituras do que escreve para o meu mestre ArrayList). Isso é bom para leitura, mas o que muitos tópicos do fórum não mencionam é que elementos podem ser adicionados, definidos ou removidos do próprio iterador. Por exemplo (uma versão básica, mas imagine em um ambiente multi-thread):
public static void main(String[] args) {
class TestObject{
private String s = "";
public TestObject(String s){
this.s = s;
}
public void setTheString(String s){
this.s = s;
}
public String getTheString(){
return s;
}
}
CopyOnWriteArrayList<TestObject> list = new CopyOnWriteArrayList<TestObject>();
list.add(new TestObject("A"));
list.add(new TestObject("B"));
list.add(new TestObject("C"));
list.add(new TestObject("D"));
list.add(new TestObject("E"));
ListIterator<TestObject> litr = list.listIterator();
while(litr.hasNext()){
TestObject test = litr.next();
if(test.getTheString().equals("B")){
litr.set(new TestObject("TEST"));
}
}
}
a linha "litr.set (new TestObject (" TEST "));" jogaria um
java.lang.UnsupportedOperationException
E olhando para a documentação do Java, há uma linha específica descrevendo esse comportamento:
"As operações de alteração de elemento nos próprios iteradores (remover, definir e incluir) não são suportadas. Esses métodos executam UnsupportedOperationException."
Então você é forçado a modificar essa lista usando
list.set(litr.previousIndex(), new TestObject("TEST"));
Agora, tecnicamente, isso não deveria apresentar um problema de sincronização? Se outro thread viesse ao mesmo tempo e, digamos, removesse todos os elementos de "list", o iterador não veria isso, iria definir a "lista" em um determinado índice e lançaria uma exceção porque o elemento nesse ponto não existe mais. Eu simplesmente não entendo o ponto de CopyOnWriteArrayList se você não puder adicionar um elemento através do próprio iterador.
Estou perdendo o ponto de usar CopyOnWriteArrayList?
Eu envolvo cada iterador que acaba tendo que adicionar / definir / remover um elemento em um bloco sincronizado?
Este tem de ser um problema comum com multi-threading. Eu teria pensado que alguém teria feito uma aula que pudesse lidar com tudo isso sem se preocupar ...
Agradecemos antecipadamente por dar uma olhada nisso!