[Perguntas da entrevista sobre Android] Perguntas principais da entrevista sobre o Android Framework - O princípio do ThreadLocal e como ele é aplicado no Looper?

O princípio do ThreadLocal e como ele é aplicado no Looper? (ByteDance, Xiaomi)

O que você deseja examinar com esta pergunta?

ThreadLocal deve ser dominado. Isso ocorre porque o princípio de funcionamento do Looper tem muito a ver com ThreadLocal. Compreender a implementação de ThreadLocal nos ajudará a entender o princípio de funcionamento do Looper. Este artigo começará com o uso de ThreadLocal. Acompanhe todos passo a passo. passo para entender o ThrealLocal.

Pontos de conhecimento para investigar

  1. O funcionamento interno do ThreadLocal
  2. Conhecimento relacionado ao Looper

Como os candidatos devem responder

ThreadLocal pode salvar um objeto em um thread especificado.Depois que o objeto é salvo, os dados salvos só podem ser obtidos no thread especificado e os dados não podem ser obtidos por outros threads. ThreadLocal raramente é usado no desenvolvimento diário, mas o sistema o utiliza no mecanismo Handler para garantir que cada thread do Handler tenha um objeto Looper independente para entender melhor o mecanismo do Handler.

O que é ThreadLocal

ThreadLocal é uma classe sobre como criar variáveis ​​locais de thread.

Na verdade, o escopo desta variável é o thread e não pode ser acessado por outros threads. Normalmente as variáveis ​​que criamos podem ser acessadas por qualquer thread, mas as variáveis ​​criadas usando ThreadLocal só podem ser acessadas pelo thread atual e não podem ser acessadas por outros threads.

Então, como o ThreadLocal garante que apenas o thread atual possa acessá-lo? Vamos primeiro analisar as duas funções mais importantes em ThreadLocal, get() e set().

Primeiro, observe o código-fonte no método get()

public T get() {
    
    
	Thread t = Thread.currentThread();  //code 1
	ThreadLocalMap map = getMap(t);
	if (map != null) {
    
    
		ThreadLocalMap.Entry e = map.getEntry(this);
		if (e != null) {
    
    
			@SuppressWarnings("unchecked")
			T result = (T)e.value;
			return result;
		}
	}
	return setInitialValue();
}

public void set(T value) {
    
    
	Thread t = Thread.currentThread();  //code 2
	ThreadLocalMap map = getMap(t);
	if (map != null)
		map.set(this, value);
	else
		createMap(t, value);
}

ThreadLocalMap getMap(Thread t) {
    
    
	return t.threadLocals;
}
    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
    
    
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

A partir de code1 e code2, deve ser fácil descobrir que ao definir ou obter o valor de ThreadLocal, o thread atual será obtido primeiro e, em seguida, getMap(thread) será chamado com base no thread. O que getMap retorna é a variável de membro threadLocals do thread thread. Portanto, a função correspondente é executada através de get e set, o que garante que o acesso a threadLocal só possa acessar ou modificar o valor do thread atual, o que garante que esta variável seja uma variável local do thread.

Então, qual é o próximo ThreadLocalMap?

O que é ThreadLocalMap
static class ThreadLocalMap {
    
    
    static class Entry extends WeakReference<ThreadLocal<?>> {
    
    
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
    
    
            super(k);
            value = v;
        }
    }
    private Entry[] table;
    //省略部分代码
    }

Pode-se ver no código-fonte que ThreadLocalMap é um array, e o array contém Entry herdado de referências fracas. Referências fracas também são usadas para que a memória possa ser recuperada quando ocorrerem situações anormais, como loops infinitos.

Vamos voltar e dar uma olhada no código fonte de set()

public void set(T value) {
    
    
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

O código aqui é muito claro. Ele retira o ThreadLocalMap de acordo com o thread atual e depois executa a operação de armazenamento de dados. Se o Mapa estiver vazio, ele é criado primeiro e depois atribuído.

Explorar map.set()

private void set(ThreadLocal<?> key, Object value) {
    
    
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);

    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
    
    
        ThreadLocal<?> k = e.get();

        if (k == key) {
    
    
            e.value = value;
            return;
        }

        if (k == null) {
    
    
            replaceStaleEntry(key, value, i);
            return;
        }
    }

    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}

Int i = key.threadLocalHashCode & (len-1) no código é igual ao método de valor hash da chave no HashMap, principalmente para evitar conflitos de valor hash. Indo mais abaixo, existem três situações ao percorrer o Mapa: 1. Encontrar uma chave existente que seja válida, e então atribuir um valor; 2. Encontrar uma chave existente, mas é inválida, substituir a Entrada expirada; 3. Se a mesma o valor da chave não for encontrado, crie uma nova entrada e atribua um valor.

Então, como o ThreadLocal é usado no Looper?

Aplicação de ThreadLocal no Looper

Encontre o código-fonte do Looper

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 private static void prepare(boolean quitAllowed) {
    
    
        if (sThreadLocal.get() != null) {
    
    //code 1
            throw new RuntimeException("Only one Looper may be create per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));// code 2
    }

O relacionamento entre Looper e threads é um para um. Os objetos Looper são isolados entre threads diferentes. Então, como o Looper garante isso? Através do código acima, deve ser fácil descobrir que a inicialização do Looper deve chamar a função de preparação.Quando a função de preparação é chamada, o código será executado no código 1. No código 1, ele primeiro determinará se o valor do looper existe no ThreadLocal do thread atual. Se existir, então uma exceção é lançada. Esta execução garante que um thread definirá Looper apenas uma vez. O fluxo de execução deste código garante que um thread tenha apenas um ThreadLocal e um ThreadLocal tenha apenas um looper.

Resumir

ThreadLocal é uma classe que cria variáveis ​​​​locais de thread. Seu mecanismo de implementação determina que o escopo desta variável é o thread e não pode ser acessado por outros threads. Usando este mecanismo, você pode garantir que um thread tenha apenas uma variável ThreadLocal. Então, através do design da função prepare no looper, é garantido que um ThreadLocal será vinculado apenas a um Looper. Através desses dois métodos, é garantido que um thread possua apenas uma variável ThreadLocal, e uma variável ThreadLocal possua apenas um Looper, formando assim uma correspondência um-para-um.


afinal

Eu compilei uma coleção de perguntas de entrevista sobre Android. Além das perguntas de entrevista acima, também inclui [ noções básicas de Java, coleções, multi-threading, máquinas virtuais, reflexão, genéricos, programação simultânea, os quatro componentes principais do Android, tarefas assíncronas e mensagens mecanismos, desenho de UI, ajuste de desempenho, SDN, estrutura de terceiros, padrão de design, Kotlin, rede de computadores, processo de inicialização do sistema, Dart, Flutter, algoritmo e estrutura de dados, NDK, H.264, H.265. Codec de áudio, FFmpeg , OpenMax, OpenCV, OpenGL ES ]
Insira a descrição da imagem aqui

Amigos necessitados podem escanear o código QR abaixo para receber todas as perguntas da entrevista + análise de respostas gratuitamente! ! !

Acho que você gosta

Origin blog.csdn.net/datian1234/article/details/133495909
Recomendado
Clasificación