Quando um objeto altera seu estado de acessibilidade, uma referência ao objeto pode ser colocada em uma fila de referência. Essas filas são usadas pelo coletor de lixo para se comunicar com nosso código sobre as alterações na acessibilidade do objeto. Essas filas são a melhor maneira de detectar alterações de acessibilidade, embora também possamos detectar alterações de acessibilidade do objeto, verificando se o valor de retorno do método get é nulo.
Objetos de referência podem ser associados a filas específicas quando construídas. Cada subclasse de referência fornece construtores do seguinte formulário:
Referência de Força Pública (referência t, Referencequeueq): Este método cria um novo objeto de referência com o objeto de referência fornecido e registra o objeto de referência na fila fornecida. Referências fracas e referências suaves são inseridas na fila depois que o coletor de lixo determina que seus objetos de referência entram no estado específico da acessibilidade que eles representam, e ambas as referências são limpas antes da fila de inserção. As referências virtuais também serão inseridas na fila após o coletor de lixo determinar que seus objetos de referência entraram no estado virtual alcançável, mas não serão limpos. Depois que o objeto de referência é inserido na fila pelo coletor de lixo, o valor de retorno de seu método GET será definitivamente nulo, para que o objeto nunca possa ser ressuscitado.
O registro de um objeto de referência em uma fila de referência não cria uma referência entre a fila e o objeto de referência. Se nosso próprio objeto de referência se tornar inacessível, ele não poderá ser inserido na fila. Portanto, nosso aplicativo precisa manter uma forte referência a todos os objetos referenciados.
A classe ReferenceQueue fornece três métodos para remover referências em uma fila:
O método da pesquisa permite que um encadeamento consulte se uma referência está em uma fila e executa uma ação específica quando a referência existe na fila. O método Remover pode lidar com situações mais complexas (menos comuns), onde um encadeamento dedicado é responsável por remover referências da fila e executar ações apropriadas. O comportamento de bloqueio desses métodos é o mesmo que o comportamento de bloqueio definido no objeto. Para uma referência específica, podemos consultar se está na fila pelo seu método isenqueed ou forçá -lo à fila chamando seu método de enoca, mas geralmente esse tipo de conector é feito pelo coletor de lixo.
As referências virtuais na fila de referência podem ser usadas para determinar quando um objeto pode ser reciclado. Não podemos acessar nenhum objeto por meio de referências virtuais, mesmo que o objeto seja acessível de outras maneiras, porque o método Get de referência virtual sempre retorna nulo. De fato, o uso de referências virtuais para encontrar o objeto a ser reciclado é a maneira mais segura, porque as referências fracas e as referências suaves serão inseridas na fila depois que o objeto pode ser encerrado, enquanto as referências virtuais são inseridas na fila quando o objeto termina é que o objeto é encerrado, que é que a fila é inserida após o último momento. Se puder, as referências virtuais devem sempre ser usadas, porque outras referências terão a possibilidade de que os métodos finalizem usem objetos endiventes.
Considere um exemplo de um gerente de recursos que pode controlar o acesso a coleções de recursos externos. Os objetos podem solicitar acesso a um recurso externo e não encerrar o acesso até que a operação seja concluída, após o que eles devem retornar o recurso usado ao gerenciador de recursos. Se esse recurso for compartilhado, seus direitos de uso serão aprovados entre vários objetos e podem até ser passados entre vários threads, por isso é difícil para determinar qual objeto é o último usuário desse recurso e, portanto, é difícil determinar qual peça de código será responsável por retornar esse recurso. Para lidar com essa situação, o gerente de recursos pode obter a reciclagem automática desse recurso associando um recurso a um objeto especial chamado de chave. Enquanto o objeto principal estiver acessível, pensamos que esse recurso ainda está em uso; Enquanto o objeto principal puder ser coletado como lixo, o recurso será lançado automaticamente. O código a seguir é uma representação abstrata dos recursos acima:
Recurso da interface {void use (chave do objeto, objeto… args); liberação void (); }Quando um recurso é obtido, seu principal objeto deve ser fornecido ao gerenciador de recursos. Para uma instância de recurso retornada, esse recurso só pode ser usado se obtiver sua chave correspondente. Isso garante que, após a chave ser reciclada, seu recurso correspondente não poderá mais ser usado, mesmo que o objeto de recurso que represente esse recurso ainda possa estar acessível. Observe que o objeto de recurso não armazena uma forte referência ao objeto principal, o que é importante porque isso impede que o objeto principal se torne inacessível, resultando no fato de o recurso não ser consumível. A implementação do recurso pode ser aninhada no gerente de recursos:
classe estática privada ResourceImpl implementa o recurso {int keyhash; BOOLEAN NECISTSRELEASE = FALSE ResourceImpl (chave do objeto) {keyhash = System.IdentityHashCode (key); // = Configure o recurso externo Necessário de necessidade = true; } public void use (chave do objeto, objeto ... args) {if (system.IdentityHashCode (key)! = keyhash) lançar novo ileqALARGumentException ("key horderO código de hash do objeto principal é armazenado quando o recurso é criado e, sempre que o método de uso é chamado, ele verifica se a mesma chave é fornecida. O uso real dos recursos também pode exigir sincronização, mas, por simplicidade, omitimos aqui. O método de liberação é responsável por liberar o recurso. Ele pode ser chamado diretamente pelo usuário do recurso após o uso ou pelo gerenciador de recursos quando o objeto principal não é mais referenciado. Como usaremos threads independentes para monitorar a fila de referência, o método de liberação deve ser sincronizado e várias chamadas devem ser permitidas.
O gerente de recursos real tem o seguinte formulário:
Classe final public Final ResourceManager {Final ReferenceQueue
O objeto principal pode ser qualquer objeto, que oferece aos usuários de recursos uma grande flexibilidade em comparação com o gerenciador de recursos atribuindo objetos principais. Quando o método GetResource for chamado, um novo objeto MPL de trabalho de recurso será criado e a chave fornecida para o método será passada para o novo objeto ResourceImpl. Em seguida, uma referência virtual é criada e seu objeto referencial é a chave passada para o método e, em seguida, essa referência virtual será inserida na fila de referência do gerente de recursos. Os objetos de referência e referência virtual criados no final serão armazenados na tabela de mapeamento. Esta tabela de mapeamento tem dois propósitos: um é manter todos os objetos de referência virtual acessíveis e o outro é fornecer uma maneira conveniente de consultar o objeto de recurso real associado a cada referência virtual. (Uma alternativa é a subclasse fantasma e armazenar o objeto de recursos em um campo.)
Se o objeto principal se tornar inacessível, o gerenciador de recursos usará um thread "Reaper" separado para processar o recurso. O método de desligamento "fecha" o explorador, encerrando o thread do colheitadela (em resposta a uma interrupção), fazendo com que o método GetResource lançasse uma exceção de illlestateException. Neste design simples, quaisquer referências que conectem uma fila após o fechamento do Explorer não serão processadas. O tópico real do coletor é o seguinte:
classe Reaperthread estende o thread {public void run () {// execute até interromper enquanto (true) {try {reference ref = fileue.remove (); Recurso res = null; sincronizado (ResourceManager.This) {res = refs.get (ref); Refs. remover (ref); } res .release (); ref.clear (); } catch (interruptedException ex) {break; // all done}}}}O Reaperthread é uma classe interna e o thread de colheitadeira fornecido será executado até que o gerente de recursos associado a ele esteja fechado. Os blocos de encadeamento no método Remover até que a referência virtual associada a uma chave específica seja inserida na fila de referência. Essa referência virtual pode obter uma referência ao objeto de recursos da tabela de mapeamento e, em seguida, esse par de "chave para referência" será removido da tabela de mapeamento. Imediatamente depois, seu método de liberação é chamado no objeto de recurso para liberar o recurso. afinal,
A referência virtual é limpa para que a chave possa ser reciclada.
Como alternativa ao uso de threads independentes, qualquer operação que chama o método da pesquisa na fila de referência e libera todos os recursos cujas chaves se tornaram inacessíveis podem ser substituídas pelo método GetResource ", e o método do Shutdow" também pode ser usado para executar a operação final da pesquisa. A semântica do gerente de recursos dependerá do tipo real de recursos e padrão de uso de recursos.
Os projetos usando filas de referência são muito mais confiáveis do que os projetos que usam terminações diretamente (especialmente referências virtuais). Mas precisamos lembrar que a hora e a localização exatos do objeto de referência inseridos na fila de referência não é certo, nem temos certeza de que todas as referências traváveis foram inseridas na fila de referência quando o aplicativo termina. Se precisarmos garantir que todos os recursos possam ser liberados antes que o aplicativo termine, devemos instalar o gancho de desligamento necessário ou usar outros protocolos definidos pelo aplicativo para garantir que isso seja alcançado.