Existe uma lista simultânea no JDK do Java?

277

Como posso criar uma instância simultânea de List, onde posso acessar elementos por índice? O JDK tem alguma classe ou método de fábrica que eu possa usar?

AlikElzin-kilaka
fonte
28
Por que não construtivo? Várias CopyOnWriteArrayList propostas que não foram encontradas no .Net. Você pode dizer que as duas perguntas se relacionam, mas não para fechar esta !!!
AlikElzin-kilaka
1
Não tenho ideia de por que Jarrod Roberson pensaria que era uma boa ideia pegar as edições detalhadas feitas por Stephan e revertê-las de volta à pergunta original, mal formulada. A resposta de Jarrod ainda é perfeitamente aceitável. De fato, CopyOnWriteArrayList é a única classe simultânea que implementa a Lista no JDK. Intrigado ...
Matt Passell
10
Como a resposta aceita foi a pergunta original e Stephan fez uma pergunta completamente não relacionada com um monte de código-fonte que o pôster original não incluía em nenhum lugar alterar completamente a pergunta, o que gerou mais respostas que sugeriam outras coisas além Listdaquelas especificamente especificadas no original. diz que é um requisito considerado vandalismo. Um moderador já bloqueou a pergunta por causa das pessoas que estão reclamando que as respostas não respondem a essa versão vandalizada da pergunta.
1
/ locked/ closed/ comentário anterior
8
Não há razão para esta pergunta ser encerrada. Ele pergunta sobre as classes no JDK, o que não é nada como procurar uma biblioteca; é a base do Java.
maaartinus 02/09

Respostas:

175

Há uma implementação de lista simultânea em java.util.concurrent . CopyOnWriteArrayList em particular.

Basil Bourque
fonte
84
Observe que ele copia a lista inteira em todas as inserções, portanto é muitas vezes ineficiente.
dfrankow
22
@dfrankow Mas pode mais mais eficiente se você está interagindo muito mais do que você está atualizando.
b1nary.atr0phy
Não funciona bem como mostrado aqui. Tenho exceções, embora apenas use o método addAll e o leia usando stream. stackoverflow.com/questions/1527519/…
devssh 26/03
166

Se você não se preocupa em ter acesso baseado em índice e apenas deseja as características de preservação da ordem de inserção de uma Lista, considere um java.util.concurrent.ConcurrentLinkedQueue . Como ele implementa o Iterable, quando você terminar de adicionar todos os itens, poderá percorrer o conteúdo usando a sintaxe aprimorada:

Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();

//Multiple threads can safely call globalQueue.add()...

for (String href : globalQueue) {
    //do something with href
}
Matt Passell
fonte
4
Eu acho que o simplificado para statement ( :) é chamado de foreach: docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
AlikElzin-kilaka
2
@ AlikElzin-kilaka Você está certo. Acho que esse nome sempre me incomodou, porque a sintaxe real não inclui a palavra "each", mas atualizarei a resposta para usar o nome oficial. :)
Matt Passell
3
@ AlikElzin-kilaka Nitpicking, mas de acordo com a versão 8 do JLS , é chamado de "aprimorado para declaração". O mesmo no tutorial java .
Roland
1
@Roland definitivamente NÃO nitpicking. Há (agora) uma diferença entre "para cada" e "aprimorado para" em Java.
hfontanez
2
@Roland indiretamente. Eu acredito que eles renomearam o "para cada loop" para "aprimorado para" para eliminar a confusão entre o Stream.forEach e o que agora é conhecido como aprimorado para.
precisa saber é o seguinte
128

É possível usar muito bem o Collections.synchronizedList (List) se tudo o que você precisa é de simples sincronização de chamada:

 List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
Yanick Rochon
fonte
70
O resultado de synchronizedListé "sincronizado", mas não "simultâneo". Uma questão fundamental que muitas operações da Lista - que são baseadas em índices - não são atômicas e precisam fazer parte de uma construção de exclusão mútua maior.
6
IMO, como a Vectoré mais simples do que Collections.synchronizedList(new ArrayList<Object>()).
21713 Stephan
8
O resultado de synchronizedList é "sincronizado", mas não "simultâneo".
Kanagavelu Sugumar
46

Como o ato de adquirir a posição e obter o elemento da posição especificada requer naturalmente algum bloqueio (não é possível que a lista tenha alterações estruturais entre essas duas operações).

A própria idéia de uma coleção simultânea é que cada operação por si só é atômica e pode ser feita sem bloqueio / sincronização explícita.

Portanto, colocar o elemento na posição nde uma dada Listoperação atômica não faz muito sentido em uma situação em que o acesso simultâneo é antecipado.

Joachim Sauer
fonte
6
Joachim, acho que você acertou a unha na cabeça. Tomemos, por exemplo, uma lista somente leitura como uma lista simultânea. Obter o elemento na posição N da lista não apenas faz sentido, mas também é a casca de noz do problema. Portanto, uma lista imutável (L minúscula) seria um bom exemplo, mas não é uma Lista (L maiúscula). O CopyOnWriteArrayList é simultâneo, mas muitas pessoas não gostam do desempenho. Uma solução ao longo das cordas (cordas) provavelmente seria um bom vencedor.
johnstosh
1
Muito bom ponto. Mas a lista que o OP vai usar pode ter um uso muito específico. Por exemplo, pode ser preenchido em ambiente simultâneo, depois "bloqueado" (o que quer que isso signifique) e, em seguida, acessado com segurança pelo índice. Portanto, na primeira fase do preenchimento de uma lista ainda será necessária uma implementação segura para threads. Infelizmente, o OP não foi específico sobre como a Lista que ele está procurando será usada.
Igor.zh
13

Você tem estas opções:

  • Collections.synchronizedList(): Você pode envolver qualquer Listaplicação ( ArrayList, LinkedListou uma lista de 3rd-party). O acesso a todos os métodos (leitura e escrita) será protegido usando synchronized. Ao usar iterator()ou aprimorado para o loop, você deve sincronizar manualmente; durante a iteração, outros threads são totalmente bloqueados, mesmo na leitura. Você também pode sincronizar separadamente para cada chamada hasNexte next, mas ConcurrentModificationExceptioné possível.

  • CopyOnWriteArrayList: é caro modificar, mas não tem espera para ler. Os iteradores nunca lançam ConcurrentModificationException, eles retornam um instantâneo da lista no momento da criação do iterador, mesmo que a lista seja modificada por outro encadeamento durante a iteração. Útil para listas atualizadas com pouca frequência. Operações em massa como addAllas preferidas para atualizações - a matriz interna é copiada menos vezes.

  • Vector: muito parecido synchronizedList, mas a iteração também é sincronizada. No entanto, os iteradores podem lançar ConcurrentModificationException, se o vetor for modificado por outro thread durante a iteração.

Outras opções:

  • Collections.unmodifiableList(): livre de trava, sem fio, mas não modificável
  • Queueou Dequepode ser uma alternativa se você adicionar / remover apenas no final da lista e iterar a lista. Não há acesso por índice nem adição / remoção em locais arbitrários. Eles têm várias implementações simultâneas com melhor desempenho e melhor acesso simultâneo, mas está além do escopo desta pergunta. Você também pode dar uma olhada no JCTools , eles contêm implementações de filas com melhor desempenho, especializadas para um único consumidor ou produtor único.
Oliv
fonte
4

insira a descrição da imagem aqui

CopyOnWriteArrayList é uma variante segura de thread de ArrayList na qual todas as operações mutativas (adicionar, definir e assim por diante) são implementadas fazendo uma nova cópia da matriz subjacente.

O CopyOnWriteArrayList é uma alternativa simultânea da interface List implementada e a parte sincronizada do pacote java.util.concurrent e é uma coleção segura para threads.

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

CopyOnWriteArrayList é à prova de falhas e não lança ConcurrentModificationException quando CopyOnWriteArrayList subjacente é modificado durante a Iteração, use uma cópia separada de ArrayList.

Isso geralmente é muito caro, porque a matriz de cópias envolve todas as operações de atualização em que uma cópia clonada será criada. CopyOnWriteArrayList é a melhor opção apenas para operação de leitura frequente.

/**
         * Returns a shallow copy of this list.  (The elements themselves
         * are not copied.)
         *
         * @return a clone of this list
         */
        public Object clone() {
            try {
                @SuppressWarnings("unchecked")
                CopyOnWriteArrayList<E> clone =
                    (CopyOnWriteArrayList<E>) super.clone();
                clone.resetLock();
                return clone;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }
vaquar khan
fonte