Experiência de estágio unilateral em Matemática Jingdong

Jingdong Mathematics (11h, 13 de janeiro de 2021)

O entrevistador foi muito bom, todo o processo foi paciente e me ouviu e analisou comigo.Foi uma experiência de entrevista muito gratificante.
Tempo total da entrevista: 43 minutos

  1. Auto apresentação

    (Eu não falei sobre o projeto ... talvez seja muito simples olhar para a pilha de tecnologia)

  2. Basta perguntar o que você sabe sobre JVM?

    Resposta: não entendo

  3. Uma pergunta sobre TCP / IP

    Resposta: Não (não ouvi claramente e não me preparei para este, então apenas disse não)

    De acordo com o currículo, escrevi familiaridade com multithreading e perguntei ...

  4. Você aprendeu sobre o CAS?

    Resposta: √

    CAS (Compare-and-Swap), ou seja, compare e substitua, é uma tecnologia comumente usada na implementação de algoritmos concorrentes.Muitas classes em pacotes simultâneos Java usam a tecnologia CAS.

    As operações CAS precisam contar com os métodos da classe Unsafe. Todos os métodos da classe Unsafe são modificados nativamente e todos os métodos chamam diretamente os recursos subjacentes do sistema operacional para realizar tarefas. O CAS é uma primitiva de simultaneidade da CPU e, no sistema operacional, a execução da primitiva deve ser contínua e nenhuma interrupção é permitida durante a execução, o que significa que o CAS é uma instrução atômica.

    O CAS precisa ter 3 operandos: endereço de memória V, antigo valor esperado A e valor alvo B a ser atualizado.

    Quando a instrução CAS é executada, se e somente se o valor do endereço de memória V for igual ao valor esperado A, o valor do endereço de memória V é modificado para B, caso contrário, ele não faz nada. Toda a comparação e operação de substituição é uma operação atômica.

  5. Quais são as desvantagens do CAS?

    Resposta: √ Eu disse três

    1. Loop infinito afeta o desempenho

    2. Garanta apenas a atomicidade de uma variável compartilhada

    3. Problema ABA

  6. Você pode me falar sobre o problema ABA?

    Resposta: √ Há uma breve descrição, mas também dou um exemplo para ilustrar.

    O processo CAS é geralmente o seguinte:

    1. Leia primeiro A a partir do endereço V
    2. Calcule o valor alvo B de acordo com A
    3. Altere o valor do endereço V de A para B de maneira atômica por meio de CAS

    O valor lido na etapa 1 é A e a modificação foi bem-sucedida na etapa 3. Podemos dizer que seu valor não foi alterado por outros threads entre as etapas 1 e 3?

    Se seu valor foi alterado para B durante este período e, em seguida, alterado novamente para A, a operação CAS acreditará erroneamente que ele nunca foi alterado. Essa vulnerabilidade é chamada de problema "ABA" das operações CAS.

  7. Como resolver o problema ABA?

    Resposta: √

    Para resolver esse problema, o Java Concurrent Package fornece uma classe de referência atômica marcada "AtomicStampedReference", que pode garantir a correção do CAS controlando a versão do valor da variável. Portanto, antes de usar o CAS, você deve considerar se o problema "ABA" afetará a exatidão da simultaneidade do programa. Se você precisar resolver o problema ABA, mudar para a sincronização mutuamente exclusiva tradicional pode ser mais eficiente do que as classes atômicas.

  8. Então você usa a referência atômica AtmoicRefence para explicar o exemplo agora. Como resolver isso?

    Resposta: Meio √, acho que não respondi. Mais tarde, pensei sobre isso. Deveria ser que eu quisesse me atrair para isso e isso não poderia resolver completamente o problema ABA. A solução final foi usar AtomicStampRefence para apresentar o mecanismo de número de versão (sou um idiota ...)

    No pacote de simultaneidade java.util.concurrent.atomic no JDK, é fornecido AtomicStampedReference . Ao estabelecer um número de versão semelhante ao Stamp para a referência, ele pode resolver o problema ABA no mecanismo CAS.

    Leia o código-fonte! ! !

    Em primeiro lugar, existem quatro parâmetros na função compareAndSet de AtomicStampedReference. Observe o código-fonte:

    compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)

    1. EsperadaReferência: indica o valor esperado
    2. newReference: o valor a ser atualizado
    3. carimbo esperado: carimbo de data / hora esperado
    4. newStamp: carimbo de data / hora atualizado

Insira a descrição da imagem aqui
Aqui, descobriremos que apenas a referência de valor e o carimbo de data e hora são armazenados no Par. A Insira a descrição da imagem aqui
chave está no método casPair, que consiste principalmente em usar o mecanismo CAS para atualizar a nova referência de valor e o carimbo de data e hora.
Insira a descrição da imagem aqui
9. Então eu digo que o CAS depende do método da classe Unsafe.A camada inferior é implementada em C ++. Você pode me dizer como implementá-la em C ++?

答 : O que ?? C ++ ?? Vejo você

A classe de pacote inseguro é sun.misc.Unsafe

img

  1. Você conhece o pool de threads em multithreading?

    Resposta: Depois de algumas palavras simples, ele não me deixou envergonhado ...

    Não há resposta aqui, sugiro entender estas questões:

    1. O que é pool de threads
    2. Por que existe um pool de threads? Qual é o objetivo principal de resolver o problema e os benefícios do pool de threads?
    3. Olhe para o código fonte
    4. Otimização do pool de threads
    5. Como criar um pool de threads?

  2. Você conhece palavras-chave voláteis?

    Resposta: √ (Olhando para a entrevista, descobri que os entrevistadores da JD Mathematics sempre perguntam isso, então eu revisei cuidadosamente na noite passada)

    Volatile é um mecanismo de sincronização leve fornecido pela máquina virtual Java. As variáveis ​​definidas por Volatile são lidas da memória principal toda vez que o sistema o usa, em vez da memória de trabalho de cada encadeamento. Possui três características:

    • Visibilidade da memória

    • Sem garantia de atomicidade

    • Proibir reorganização de ordem

    1. Visibilidade da memória

    A operação de cada thread na variável compartilhada na memória principal é a operação de cada thread copiando para sua própria memória de trabalho e depois gravando de volta na memória principal

    1. Sem garantia de atomicidade

    Indivisível, completo, ou seja, quando um thread está fazendo um negócio específico, o tempo não pode ser bloqueado ou dividido. Precisa ser completo como um todo para ter sucesso ou falhar ao mesmo tempo

    Por exemplo: crie 20 threads, cada thread i ++ 1000 operações causará problemas (como resolver? 1. Adicionar sincronizado 2. Use o método AtmoicInteger.getincrement () da classe atômica)

    1. Proibição de reorganização da ordem ("ordem")

    Em um ambiente multi-threaded, os threads são executados alternadamente. Devido ao reordenamento da otimização pelo compilador, é impossível determinar se as variáveis ​​utilizadas pelos dois threads podem ser consistentes, e o resultado é imprevisível.

  3. Fale sobre a "visibilidade da memória" em seus recursos?

    Resposta: √ Ei, eu fiz muitas pesquisas. De acordo com meu próprio entendimento, posso dizer isso facilmente

    Quando uma variável é modificada por volatile, a modificação nela será imediatamente liberada para a memória principal.Quando outros threads precisam ler a variável, eles irão para a memória para ler o novo valor. As variáveis ​​comuns não podem garantir isso.

    Sugestão: Quando o entrevistador lhe fizer esta pergunta, você deve responder da seguinte forma: Fale-me sobre o modelo de memória Java, porque sua existência leva à existência de problemas de visibilidade, introduzindo assim a visibilidade do Volatile!

  4. Você pode me dizer como isso é implementado no nível inferior?

    Resposta: Uh ... eu não sei ... Olhe o que eu disse suavemente e comece a me foder

    Anteriormente, dissemos que quando as tarefas de computação de vários processadores envolvem a mesma área de memória principal, isso pode levar a inconsistências em seus respectivos dados de cache.Um exemplo é o compartilhamento de variáveis ​​entre várias CPUs.

    Se isso acontecer, quais dados em cache prevalecerão ao sincronizar de volta para a memória principal?

    Para resolver o problema de consistência, cada processador precisa seguir alguns protocolos ao acessar o cache e operar de acordo com o protocolo ao ler e escrever, como MSI MESI(IllinoisProtocol),, MOSI, Synapse, Firefly e DragonProtocol.

    MESI (Protocolo de Coerência de Cache)

    Quando a CPU grava dados, se a variável operacional for uma variável compartilhada, ou seja, existe uma cópia da variável em outras CPUs, ela enviará um sinal para notificar outras CPUs para invalidar a linha de cache da variável, então quando outras CPUs precisam ler Quando você busca esta variável, se você descobrir que a linha de cache que armazena a variável em seu cache é inválida, então ele a lerá da memória novamente.

    Sobre como descobrir se os dados são inválidos?

    Farejar

    Cada processador verifica se o valor de seu cache expirou ao farejar a disseminação de dados no barramento. Quando o processador descobrir que o endereço de memória correspondente à sua linha de cache foi modificado, ele definirá a linha de cache do processador atual como inválida. Estado , quando o processador modificar esses dados, ele lerá os dados da memória do sistema para o cache do processador novamente.

    Tempestade de ônibus

    Como o protocolo de coerência de cache MESI do Volatile requer um sniffing contínuo da memória principal e um loop contínuo de cas, a interação inválida fará com que a largura de banda do barramento atinja seu pico.

    Portanto, não use Volátil em grandes quantidades, quanto a quando usar Volátil e quando usar fechaduras, diferencie de acordo com a cena.

  5. O AQS entende?

    Resposta: Apenas algumas palavras (meu progresso não está aqui ainda ...)

  6. A diferença entre thread e processo?

    Resposta: √

    1. Processo é a unidade básica de alocação de recursos; thread é a unidade básica de execução do programa.
    2. Um processo tem seu próprio espaço de recursos. Cada vez que um processo é iniciado, o sistema aloca um espaço de endereço para ele; os threads não têm nada a ver com a alocação de recursos da CPU. Vários threads compartilham os recursos no mesmo processo e os usam espaço de endereço.
    3. Um processo pode conter vários threads
  7. Como se comunicar entre processos? (Eu quero que você se orgulhe ... veja se você consegue)

    Resposta: Eu disse IPC, só vi acidentalmente e esqueci

    A comunicação entre processos (IPC, comunicação entre processos) é um conjunto de interfaces de programação,

    Permite que os programadores coordenem diferentes processos para que possam ser executados simultaneamente em um sistema operacional e transferir e trocar informações entre si.

    Os métodos IPC incluem tubos (PIPE), filas de mensagens, sinais, memória compartilhada e soquetes.

    Você é um estranho multi-threaded? Não aguento mais

  8. Você sabe sobre bloqueios reentrantes? É a fechadura reentrante no JUC

    Resposta: em ... Eu não sei se isso significa sincronizado e ReetrentLock bloqueia

    https://blog.csdn.net/w8y56f/article/details/89554060

  9. Fale-me sobre ReetrentLock

    Resposta: √ Quase tudo dito, e uma comparação simples com o sincronizado

    https://zhuanlan.zhihu.com/p/65727594

  10. Conte-me sobre sua compreensão de bloqueios justos e bloqueios injustos

    Resposta: √

    simplesmente diga:

    1. Bloqueio justo: garanta justiça absoluta, os fios vêm primeiro, vêm primeiro
    2. Bloqueio injusto: muito injusto, você pode pular na fila

    O padrão diz:

    Bloqueio justo: vários threads adquirem bloqueios na ordem em que se aplicam aos bloqueios. Os threads entrarão diretamente na fila para fazer fila e serão sempre os primeiros na fila a obter o bloqueio.

    • Vantagens: Todos os threads podem obter recursos e não morrerão de fome na fila.
    • Desvantagens: a taxa de transferência cairá muito, exceto para o primeiro encadeamento na fila, outros encadeamentos serão bloqueados e a sobrecarga da cpu ativando os encadeamentos bloqueados será muito grande.

    Bloqueio injusto: quando vários threads adquirem um bloqueio, eles tentarão adquiri-lo diretamente. Se não puderem adquiri-lo, entrarão na fila de espera. Se conseguirem obter o bloqueio, eles o adquirirão diretamente.

    • Vantagens: Pode reduzir a sobrecarga da CPU que ativa os threads, e a eficiência geral do throughput será maior. A CPU não precisa despertar todos os threads, o que reduzirá o número de threads a serem chamados.
    • Desvantagens: você também pode ter descoberto que isso pode fazer com que o encadeamento no meio da fila não consiga adquirir o bloqueio ou adquiri-lo por um longo tempo, resultando em inanição.
  11. Qual você acha que é mais eficiente? porque?

    Resposta: Acho que deve estar errado. Ele analisou comigo por muito tempo

    Os bloqueios justos precisam manter uma fila e os threads subsequentes precisam ser bloqueados. Mesmo se o bloqueio estiver livre, primeiro verifique se há outros threads em espera. Se houver algum que precise ser suspenso, adicione-o ao final da fila, e, em seguida, desperte o thread da frente da fila. Neste caso, em comparação com o bloqueio injusto, há mais um suspender e despertar

    A sobrecarga da troca de thread é na verdade a razão pela qual bloqueios injustos são mais eficientes do que bloqueios justos, porque bloqueios injustos reduzem a probabilidade de suspensão de thread e threads subsequentes têm uma certa chance de escapar da sobrecarga suspensa.

    Ok, acho que você pode ter uma compreensão mais profunda da simultaneidade multi-threaded ...

  12. Vamos falar sobre coleções, você conhece HashMap?

    Resposta: √ (Vamos lá, vou me mexer, comi muito bem desde a última vez que li o byte)

    HashMap usa matrizes Entry para armazenar valores-chave. Cada par de valores-chave forma uma entidade Entry (jdk1.7, jdk1.8 alterado para Node). A classe Entry é, na verdade, uma estrutura de lista vinculada unilateral, que tem um próximo ponteiro ., Você pode se conectar à próxima entidade de entrada. No JDK 1.8, quando o comprimento da lista vinculada é maior que 8, a lista vinculada será convertida em uma árvore vermelho-preto!

  13. Conte-me sobre todo o processo de seu método put, certo?

    Resposta: √

    1. Chame a função hash do objeto para obter o valor hash correspondente à chave e, a seguir, calcule o subscrito da matriz;
    • Se não houver conflito de hash, coloque-o diretamente na matriz
    • Se houver um conflito de hash, coloque-o atrás da lista vinculada na forma de uma lista vinculada
    1. Se o comprimento da lista vinculada exceder o limite (TREEIFY THRESHOLD == 8), a lista vinculada é convertida em uma árvore vermelho-preto. Quando o comprimento da lista vinculada é menor que 6, volte a árvore vermelho-preto para a lista vinculada;

    2. Se a chave do nó já existir, substitua o valor do valor;

    3. Se o número de pares de valores-chave na coleção for maior que 12, chame o método resize para expandir a matriz

    De acordo com o código-fonte que você leu e seu próprio entendimento, basta dizê-lo passo a passo.

  14. Como isso se expande? Vamos falar sobre o mecanismo de expansão

    Resposta: √

    Capacidade padrão = 16, fator de carga = 0,75f

    Depois de atingir o limite = capacidade * fator de carga, ele é expandido para 2 vezes.

    Depois de refazer o hash, recalcule o subscrito. Dependendo de os resultados antes e depois da repetição serem os mesmos, ela é dividida em lista vinculada baixa e lista vinculada alta para repetição

  15. Como o código específico é implementado?

    Resposta: √

    Execute uma operação de bit no tamanho original e desloque um bit para a esquerda

  16. Por que você diz que o tamanho da expansão deve ser uma potência de 2?

    Resposta: √ Como a operação AND é usada, a eficiência do cálculo do valor de hash é melhorada

    Porque o algoritmo de HashMap para encontrar a posição do balde correspondente usa a operação AND em vez da operação tradicional de módulo

    A premissa de hash% length == hash & (length-1) é que o comprimento é uma potência de 2.

  17. Você disse que se o comprimento da lista vinculada chegar a 8, ela será convertida em uma árvore vermelho-preta. Por que é 8?

    Resposta: √ Eu disse a partir de muitos aspectos, a distribuição de Poisson da teoria da probabilidade e desempenho de pesquisa. Deve estar certo ... porque não diz nada

    1. De acordo com a distribuição de Poisson, quando o fator de carga é 0,75, a probabilidade de que o número de elementos em um único slot de hash seja 8 é menor que um em um milhão
    2. Quando o comprimento é 8, em vez de garantir a sobrecarga de pesquisa da estrutura da lista vinculada, é melhor converter para uma árvore vermelho-preto e manter seu equilíbrio geral.
  18. Qual é a complexidade do tempo de pesquisa da árvore vermelho-preto?

    Resposta: √

    O (logN)

    em ... este entende muito bem, então eu não vou te perguntar

    O que eu pensei em meu coração, não ... Você não gosta de perguntar sobre multithreading? Não fale sobre a segurança de thread do HashMap?

  19. (Em seguida, vou olhar para o algoritmo novamente e começar a brincar comigo) Você entende os problemas clássicos de TopK? Como você resolve isso?

    Resposta: Meio √, deveria estar bem aqui, sou autista ... respondi pilha mínima, seleção rápida, hash

  20. Hash falar sobre o processo

    Resposta: Eu dei um exemplo e falei sobre o processo (não sei, certo?)

  21. Em seguida, analise a complexidade de tempo do seu hash

    Resposta: Estou morto ... Não entendi o processo agora, ele entendeu?

    Questão retórica

    1. Qual departamento? Qual é o número de ciência e tecnologia em Taiwan

    2. Você pode me dar um breve comentário sobre a avaliação da minha entrevista? Ou no que devo prestar atenção no futuro?

      Resposta: Você precisa aprender um pouco mais sobre a simultaneidade multithread (como pool de threads, AQS, etc.) e é recomendável se preparar bem para o algoritmo.

    Minha própria sensação: o frio deve ser frio. Mas como dizer, respondendo a algumas perguntas, sinto que a preparação diária durante este período também é gratificante, pelo menos saberei quais aspectos precisam de um estudo e pesquisa mais aprofundados. Afinal, o tempo de preparação realmente não é longo (formalmente e seriamente preparado no dia 1.9, apenas ... no quarto dia). Continue trabalhando duro! ! !

Acho que você gosta

Origin blog.csdn.net/weixin_44723496/article/details/112585718
Recomendado
Clasificación