Compreendendo java.lang.Thread.State: WAITING (parking)


91

Primeiro, uma pergunta realmente idiota, eu estava me perguntando o que o 'estacionamento' em espera significa? O thread está esperando para ser estacionado ou acabou de ser estacionado e, portanto, está no estado de espera? E quando esse estacionamento acontecer, quantos recursos de CPU / memória serão usados? Qual é o propósito de estacionar um fio?

Em segundo lugar, olhando para o método park na API de thread Java

Desativa o thread atual para fins de agendamento de thread, a menos que a permissão esteja disponível.

Se a licença estiver disponível, ela é consumida e a chamada retorna imediatamente; caso contrário, o thread atual será desabilitado para fins de agendamento de thread e ficará inativo até que uma das três coisas aconteça ...

Inglês não é meu idioma principal, então tenho algumas dificuldades em entender que, eu pretendia 'permitir' como uma espécie de 'permissão para estacionar o fio', então as perguntas a seguir:

  • qual é o significado disso, o que é 'licença' e quem e como está verificando essas licenças?
  • O que isso significa: 'se a licença estiver disponível, então ela será consumida', está ficando 'estacionada'?
  • a seguir, se o segundo ponto for verdadeiro, então qual é a diferença entre 'estacionar' e 'ficar dormente'? Se eu tiver permissão, posso estacioná-lo para sempre e, se não, posso deixá-lo 'inativo'?

obrigado

Respostas:


37

Permitir significa uma permissão para continuar a execução. O estacionamento significa suspender a execução até que a licença esteja disponível.

Ao contrário Semaphoredas permissões de, as permissões de LockSupportestão associadas a threads (isto é, a permissão é dada a uma thread em particular) e não se acumulam (ou seja, pode haver apenas uma permissão por thread, quando a thread consome a permissão, ela desaparece).

Você pode permitir um tópico chamando unpark(). Um encadeamento pode suspender sua execução até que a permissão esteja disponível (ou o encadeamento seja interrompido ou o tempo limite expirado, etc.) chamando park(). Quando a permissão está disponível, o thread estacionado a consome e sai de um park()método.


2
Assumindo então, se o thread A chamar 'estacionar' para o thread B, mas permitir estiver disponível, que é 'B não pode ser estacionado', então a chamada feita por A simplesmente retorna e B não é estacionado. Caso contrário, quando nenhuma licença estiver disponível, B tem que obedecer. Então, a espera (estacionamento) significa "A está tentando me estacionar porque não tenho permissão, mas não posso fazer isso agora, então estou bloqueando A também"? Desculpe por esta longa frase. Suponho que essa espera consome muitos recursos. Ainda estou me perguntando quem está gerenciando toda essa coisa de licença. Quem / o que está decidindo que algum tópico tem permissão, enquanto outros não.
— Leonardo

2
@Leonardo: Um thread só pode se estacionar, não há como estacionar outros threads. Portanto, chamar park()significa "Quero suspender minha execução até que algum outro encadeamento me dê uma permissão chamando unpark()".
— axtavt

Portanto, um thread não pode estacionar outros threads, mas pode ser desestacionado por outros threads? Isso está correto? Então, quando esse estacionamento ocorre? Talvez um segmento não tenha trabalho a fazer no momento, e sua maneira de verificá-lo é olhando constantemente para sua licença? Isso seria adequado para thread daemon, por exemplo.
— Leonardo

Além disso, WAITING (estacionamento) significa que está aguardando para ser estacionado ou está em um estado de espera após ser estacionado? Desculpe, eu sei que esta é uma pergunta idiota :-)
— Leonardo

3
@Leonardo: Significa um estado de espera após o estacionamento.
— axtavt

11

De acordo com a documentação do estado do thread java , um thread pode ir para o estado WAITING por três motivos:

  1. Object.wait sem tempo limite
  2. Thread.join sem tempo limite
  3. LockSupport.park

Quando você chama um método de estacionamento em um Thread, ele desativa o thread para fins de agendamento de thread, a menos que a permissão esteja disponível. Você pode chamar o método unpark para disponibilizar a permissão para o encadeamento fornecido, se ainda não estiver disponível.

Portanto, quando seu Thread estiver no modo WAITING por LockSupport.park, ele mostrará como WAITING (parking).

Observe que você só pode chamar o estacionamento no Tópico atual. Este é um mecanismo muito útil para implementar o Padrão de Design Produtor-Consumidor.


3

Na descrição da classe (no topo do javadoc LockSupport ), onde descreve a licença:

Esta classe associa a cada thread que a usa, uma permissão (no sentido da classe Semaphore). Uma chamada para estacionar retornará imediatamente se a licença estiver disponível, consumindo [a licença] no processo; caso contrário, [a chamada para estacionar] pode bloquear. Uma chamada para desestacionar disponibiliza a licença, se ainda não estiver disponível. (Ao contrário dos semáforos, as licenças não se acumulam. Há no máximo um.)

(Eu expandi o [texto] para torná-lo mais fácil de ler para quem não fala inglês.)

Esperançosamente, alguém com uma compreensão mais profunda pode elaborar sobre isso. Veja a resposta de axtavt.

Como nota final, uma citação final do javadoc:

Esses métodos são projetados para serem usados ​​como ferramentas para a criação de utilitários de sincronização de alto nível e não são úteis em si mesmos para a maioria dos aplicativos de controle de simultaneidade.


3

A parte que me fez revisitar essa questão que não consegui contornar ao ler a documentação foi:

Se a licença estiver disponível, ela é consumida e a chamada retorna imediatamente ...

Então, quando a licença está "disponível", quem e como a disponibiliza, para que possa ser consumida imediatamente? Isso foi de alguma forma trivial de descobrir:

public static void main(String[] args) {

    Thread parkingThread = new Thread(() -> {
        System.out.println("Will go to sleep...");
        sleepTwoSeconds();
        System.out.println("Parking...");
        // this call will return immediately since we have called  LockSupport::unpark
        // before this method is getting called, making the permit available
        LockSupport.park();
        System.out.println("After parking...");
    });

    parkingThread.start();

    // hopefully this 1 second is enough for "parkingThread" to start
    // _before_ we call un-park
    sleepOneSecond();
    System.out.println("Un-parking...");
    // making the permit available while the thread is running and has not yet
    // taken this permit, thus "LockSupport.park" will return immediately
    LockSupport.unpark(parkingThread);

}

private static void sleepTwoSeconds() {
    try {
        Thread.sleep(1000 * 2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void sleepOneSecond() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}    

O código fala por si mesmo, o threadestá em execução, mas ainda não foi chamado LockSupport.park, enquanto alguma outra thread o chama LockSupport.unpark- tornando a permissão disponível. Depois ligamos LockSupport.parke ele retorna imediatamente, pois a licença está disponível.

Depois de pensar sobre isso, isso é um pouco perigoso, se você expõe seus threads a algum código que você não controla e esse código chama LockSupport.unparkenquanto você parkdepois disso - pode não funcionar.


Muito bom ponto, eu teria pensado que uma atividade de concessão de permissão - ou seja, chamar unpark () - só é relevante quando um thread está sendo estacionado.
— Alfred Xiao

@AlfredXiao concordou, isso é algo que me surpreendeu também, mas meio que faz sentido, eu acho.
— Eugene,

1

Pelo que entendi, a "licença" é apenas um objeto que representa se um Thread pode ser "desestacionado" ou não. E isso é verificado pelo próprio Thread (ou de JRE quando você tenta estacionar um Thread) A coisa "está consumido", eu entendo que a licença desaparece e o Thread não é desabilitado.

Acho que você deveria aprender um pouco mais sobre multithreading. Pense nisso como um dispensador com objetos chamados "permitir". Você diz a um Thread para estacionar, e o Thread verifica o dispensador, se houver uma "licença", o Thread pega e sai (sem estacionar). Se não houver "permissão" no dispensador, o Thread fica estacionado até que uma "licença" esteja disponível (e você pode colocar uma "licença" no dispensador com unpark.

Quanto ao uso de CPU / memória, acho que depende do SO, etc ...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.