Perguntas ocultas da entrevista em multithreading

Todo mundo já passou por entrevistas na procura de emprego - eu não as experimentei de qualquer maneira

Todo mundo está familiarizado com as entrevistas. Todo mundo quer encontrar um emprego. Agora, a procura de um emprego definitivamente precisa de uma entrevista. No entanto, em uma entrevista, o entrevistador costuma fazer algumas perguntas para ver se você é a pessoa de que ele precisa.

Você deseja usar o Java que aprendeu para encontrar seu trabalho ideal, e multithreading é muito importante em Java, então vamos falar sobre as perguntas da entrevista ocultas no multithreading.

1. Vários métodos de implementação de multithreading Java, o que é segurança de thread?

Existem quatro maneiras principais de implementar multithreading Java:

1. Herdar a classe Thread , a única maneira de iniciar um thread é por meio do método start () da classe Thread e chamar o método start () após a instância para iniciar

2. Implemente a interface Runnable e reescreva o método run ()

3. Implementar a interface chamável

4. Por meio do invólucro da Tarefa Futrue

A segurança do thread é o uso de um mecanismo de bloqueio durante o acesso do thread. Quando um thread acessa certos dados desse tipo, ele é protegido e outros threads não podem acessá-lo. Outros threads só podem usá-lo até que o thread tenha lido e nenhum dado aparecerá Inconsistência ou contaminação de dados.

Em segundo lugar, as características de sincronização

2.1 Atomicidade

A chamada atomicidade se refere a uma operação ou múltiplas operações, ou todas são executadas e o processo de execução não será interrompido por nenhum fator, ou não será executado.

Em Java, as operações de leitura e atribuição de variáveis ​​de tipos básicos de dados são operações atômicas, ou seja, essas operações não podem ser interrompidas, executadas ou não executadas. No entanto i++, i+=1caracteres de operação como etc. não são atômicos. Eles são divididos em várias operações, como leitura, cálculo e atribuição . O valor original pode ter sido atribuído antes que essas etapas sejam concluídas, então os dados escritos pela atribuição final estão sujos Dados, atomicidade não pode ser garantida.

Todas as operações de uma classe ou objeto modificado por synchronized são atômicas, pois o bloqueio da classe ou objeto deve ser obtido antes que a operação seja realizada, e o bloqueio não pode ser liberado até que a execução seja concluída. O processo intermediário não pode ser interrompido ( exceto para o stop()método obsoleto ), ou seja, a atomicidade é garantida.

Nota! Em entrevistas, costumo perguntar sobre a comparação de sincronizado e volátil. A maior diferença entre os dois recursos é a atomicidade. Volátil não tem atomicidade.

2.2 Visibilidade

Visibilidade significa que quando vários threads acessam um recurso, o status e as informações de valor do recurso são visíveis para outros threads.

Sincronizado e volátil têm visibilidade. Quando sincronizado bloqueia uma classe ou objeto, um thread deve primeiro obter seu bloqueio se quiser acessar a classe ou objeto, e o estado deste bloqueio é visível para qualquer outro thread, e Antes de liberar o bloqueio , a modificação da variável será liberada para a memória principal para garantir a visibilidade da variável de recurso. Se um encadeamento ocupar o bloqueio, outros encadeamentos deverão esperar que o bloqueio seja liberado no conjunto de bloqueios.

A implementação de volatile é semelhante. Variáveis ​​modificadas por volatile irão atualizar a memória principal imediatamente sempre que o valor precisar ser modificado. A memória principal é compartilhada e visível para todos os threads, de modo que garante que as variáveis ​​lidas por outros threads sejam sempre as mais recentes valor Visibilidade.

2.3 Ordem

A ordem em que o programa de valor do pedido é executado é executada sequencialmente de acordo com o código.

Sincronizado e volátil são ordenados. O Java permite que compiladores e processadores reorganizem as instruções, mas o rearranjo das instruções não afeta a ordem de um único encadeamento. Ele afeta a ordem de execução simultânea de vários encadeamentos. A sincronização garante que apenas um thread acesse o bloco de código de sincronização a cada momento, o que também determina que os threads executem o bloco de código de sincronização em uma ordem sequencial, garantindo a ordem.

2.4 Reentrada

Sincronizado e ReentrantLock são bloqueios reentrantes. Quando um encadeamento tenta operar um recurso crítico de um bloqueio de objeto mantido por outro encadeamento, ele estará em um estado bloqueado, mas quando um encadeamento solicita o recurso crítico do bloqueio de objeto mantido por si mesmo novamente, essa situação é um bloqueio reentrante. Em termos gerais, isso significa que um thread que possui o bloqueio ainda pode se candidatar ao bloqueio repetidamente.

o uso de sincronizado

Synchronized pode modificar métodos estáticos, funções de membro e também pode definir diretamente blocos de código, mas na análise final, existem apenas dois tipos de recursos bloqueados: um é um objeto e o outro é uma classe .

No processo de desenvolvimento de Java, geralmente estamos familiarizados com vários padrões de design.No padrão de design, o padrão de design singleton é o primeiro padrão de design com o qual entramos em contato e também é um padrão de design comumente usado. O padrão de design singleton é dividido em dois tipos: estilo com fome e estilo preguiçoso.Nesses dois estilos preguiçosos, há problemas de insegurança de thread.

3. Thread de estilo lento não é seguro, alterado para thread safe

      Existem várias maneiras de tornar os tópicos seguros. Entre esses métodos, blocos de código de sincronização e métodos de sincronização são nossos métodos mais comumente usados ​​para resolver a segurança de thread

      Aqui, vou dar-lhe uma revisão do homem preguiçoso no padrão de design singleton - receio que você não saiba o que é o homem preguiçoso.

      Passos para escrever preguiçoso

      ① Construtor da aula de privatização

      ② Declarar o objeto de classe atual sem inicialização

      ③ Este objeto também deve ser declarado como estático

      ④ Fornece um método estático público para retornar o objeto da classe atual

class Singleton{
    //①私有化类的构造器
    private Singleton{

    }
    //②内部提供当前类的实例
    //③此实例必须静态化
    private static Singleton single;
    //④提供公共的静态方法,返回当前类的对象
    public static Singleton getSingleton(){
       if(single == null){
        single = new Singleton();
        }
        return single;
    }
}

    Revisamos o estilo preguiçoso no padrão de design singleton, e o estilo preguiçoso acima não é seguro para threads, abaixo usamos o método de bloco de código de sincronização para alterar o estilo preguiçoso para seguro para threads

     Certamente todos vocês conhecem o fluxo preguiçoso no padrão de design singleton, então vou ser preguiçoso.

class Singleton{
    //①私有化类的构造器
    private Singleton{

    }
    //②内部提供当前类的实例
    //③此实例必须静态化
    private static Singleton single = null;
    //④提供公共的静态方法,返回当前类的对象
    public static Singleton getSingleton(){
        synchronized(Singleton.class){
       if(single == null){
        single = new Singleton();
        }
        return single;
       }
    }
}

   No entanto, embora esse método possa transformar o homem preguiçoso em thread-safety, ele é muito lento e eficiente em tudo. Assim basta!

No multithreading de Java, você já ouviu falar de monitores de sincronização. Monitores de sincronização e blocos de código de sincronização são inseparáveis. Monitores de sincronização são comumente conhecidos como bloqueios. Ao resolver a segurança do thread, os bloqueios também podem ser usados ​​para resolver problemas de segurança do thread.

Quarto, as semelhanças e diferenças entre syschronized e Lock?

       Semelhanças: Ambos podem resolver problemas de segurança de thread

       Diferença: o mecanismo sincronizado libera automaticamente o monitor de sincronização após executar o código de sincronização correspondente

                     O bloqueio precisa iniciar a sincronização manualmente (bloquear ()), enquanto o encerramento da sincronização também precisa ser implementado manualmente (desbloquear ())

      Comparação de sincronizado e bloqueado

      1. O bloqueio é um bloqueio de tela (abra e feche manualmente o bloqueio, não se esqueça de fechar o bloqueio), sincronizado é um bloqueio implícito, liberado automaticamente fora do escopo.

      2. O bloqueio tem apenas bloqueio de bloco de código, sincronizado tem bloqueio de bloco de código e bloqueio de método

      3. Usando o bloqueio de bloqueio, a JVM gastará menos tempo para agendar o encadeamento, o desempenho é melhor. E tem melhor escalabilidade (fornece mais subcategorias)

No jdk 5.0, o Lock é uma nova maneira de resolver a segurança do thread. Freqüentemente, vamos usá-lo em desenvolvimento no futuro. Embora o jdk usado pela maioria das empresas em desenvolvimento seja 1.8, mas com o progresso dos tempos, também temos muitas opções para resolver problemas de desenvolvimento. Existem muitos métodos em multithreading Java, entre os quais os métodos sleep () e wait () são usados ​​com frequência. Quando eles são chamados com sucesso, os threads serão bloqueados.

Cinco, as semelhanças e diferenças entre dormir () e esperar ()

       O mesmo ponto: uma vez que o método é executado, a thread atual pode entrar no estado de bloqueio

       diferença: 

                   1) Os dois métodos são declarados em posições diferentes: sleep () é declarado na classe Thread e wait () é declarado no Object.

                   2) Os requisitos de chamada são diferentes: sleep () pode ser chamado em qualquer cena necessária. wait () deve ser chamado em um bloco de código síncrono

                   3) Com relação à liberação do monitor de sincronização: Se ambos os métodos forem usados ​​em um bloco de código de sincronização ou um método de sincronização, sleep () não irá liberar o monitor de sincronização e wait () irá liberar o monitor de sincronização.

Neste cenário, Jiu Kuan pensa que ele aparecerá na comunicação de thread multi-thread. Quando queremos que o thread fique na fila lentamente, podemos usar dois métodos e notificar () para ativar o thread. Quando várias instruções estão operando no mesmo encadeamento para compartilhar dados, um encadeamento executa apenas parte das várias instruções e outro encadeamento participa da execução da instrução antes de sua conclusão. Erros que levam a dados compartilhados. Para instruções que compartilham dados para várias operações, apenas uma thread pode ser executada.Durante a execução, outras threads não podem participar da execução. Java fornece uma solução profissional para o problema de segurança de multithreading: mecanismo de sincronização O mecanismo de bloqueio de sincronização é para bloquear o recurso quando ele é usado por uma tarefa. A primeira tarefa para acessar um determinado recurso deve bloquear este recurso para que outras tarefas não possam acessá-lo até que seja desbloqueado, e quando é desbloqueado, outra tarefa pode bloqueá-lo e usá-lo.

6. Como Java resolve o problema de segurança de thread, de várias maneiras?

1. Sincronizar blocos de código

          O bloqueio no bloco de código de sincronização pode ser especificado por você, geralmente especificado como this ou o nome da classe.class. Qualquer objeto pode ser usado como um bloqueio de sincronização e todos os objetos contêm automaticamente um único bloqueio (monitor).
Por exemplo, multithreading é implementado implementando a interface Runnable.Como vários threads compartilham um objeto, o bloqueio de sincronização pode ser qualquer objeto neste momento. Se você usar o método de herdar Thread para implementar multithreading, uma vez que vários threads não são o mesmo objeto, você só pode usar o nome da classe .class ou objeto estático neste momento. Em suma, é necessário garantir que vários threads usando o mesmo recurso compartilhem um bloqueio. Isso é muito importante, caso contrário, a segurança dos recursos compartilhados não pode ser garantida.

2. Método de sincronização

  • Bloqueio de método síncrono: método estático (nome da classe.classe), método não estático (este)
  • Todos os métodos estáticos em uma classe de thread compartilham o mesmo bloqueio (nome da classe.classe), e todos os métodos não estáticos compartilham o mesmo bloqueio (this)

3. Bloquear (bloquear)

A partir do JDK 5.0, Java fornece um mecanismo de sincronização de encadeamento mais poderoso - a sincronização é obtida definindo explicitamente os objetos de bloqueio de sincronização. Os bloqueios de sincronização usam objetos de bloqueio para atuar como. A interface java.util.concurrent.locks.Lock é uma ferramenta para controlar vários threads para acessar recursos compartilhados. O bloqueio fornece acesso exclusivo aos recursos compartilhados. Apenas um thread pode bloquear o objeto Lock por vez. O objeto Lock deve ser adquirido antes que o thread comece a acessar o recurso compartilhado. A classe ReentrantLock implementa Lock, que tem a mesma simultaneidade e semântica de memória que o synchronized.Na realização do controle thread-safe, ReentrantLock é mais comumente usado, o que pode bloquear e liberar bloqueios explicitamente.

O bloqueio é um bloqueio explícito (abra e feche manualmente o bloqueio, não se esqueça de fechar o bloqueio), sincronizado é um bloqueio implícito, que é automaticamente liberado fora do escopo. Usando bloqueios de bloqueio, JVM gastará menos tempo para agendar threads, melhor desempenho. E tem melhor escalabilidade (fornece mais subcategorias)

7. O princípio e a função do volátil, ele pode substituir os bloqueios?

       Volátil é um leve sincronizado, o que garante a " visibilidade " das variáveis ​​compartilhadas no desenvolvimento de multiprocessadores . Visibilidade significa que quando um thread modifica uma variável compartilhada, outro thread pode ler o valor modificado. Se um campo for declarado como volátil, a obsessão da memória Java multi-threaded garante que todos os threads vejam que o valor desta variável é consistente. Existem várias características.

    A Volatle  não pode garantir a atomicidade das operações compostas . Java garante apenas as propriedades de variáveis ​​de tipo de dados básicos. As operações de atribuição são atômicas. Claro, bloqueios e sincronizados podem ser usados ​​para garantir a atomicidade. Estritamente falando, a leitura / gravação de qualquer mudança volátil única é atômica, mas as operações compostas semelhantes a volatile ++ não são atômicas .

    Volátil pode garantir visibilidade . Quando uma variável é modificada por volátil, significa que a memória local do thread é inválida. Quando um thread modifica a variável compartilhada, ela será atualizada para a memória principal. Quando outros threads lerem a variável compartilhada, Leia diretamente da memória principal. Obviamente, tanto sincronizado quanto bloqueado podem garantir visibilidade.

     Volátil pode garantir a ordem e proibir o reordenamento de instruções.

Em resumo, o volátil pode garantir a visibilidade do thread e fornecer um certo grau de ordem, mas não pode garantir a atomicidade. O volátil na parte inferior da JVM é implementado usando "barreiras de memória *.

No cenário de uso, o volátil de bloqueio leve não pode substituir o sincronizado. No entanto, em situações limitadas, as variáveis ​​de vlaile podem ser usadas em vez de bloqueios . As variáveis ​​de vlatile devem ser fornecidas. Ideal a segurança do thread deve atender às duas condições a seguir ao mesmo tempo: as
    operações de gravação em variáveis ​​não dependem do valor atual.

    Esta variável não é incluída em um invariante com outras variáveis.

 

  Recomendado

  Navegador recomendado: Google Chrome

  Ambiente Java recomendado: eclipse, IDEA

  Aprendizagem recomendada esta semana: HTML e CSS

  Link do vídeo de aprendizagem recomendado:  https://www.bilibili.com/video/BV1CK411G7m4?from=search&seid=9778818247834758128

  Ambiente HTML recomendado: VScode (Visual Studio Code)

 

 

Acho que você gosta

Origin blog.csdn.net/weixin_52011642/article/details/110570074
Recomendado
Clasificación