Ainda há uma diferença entre as variáveis ThreadLocal e Thread Member. A classe Threadlocal fornece variáveis locais de encadeamento. Essa variável local é diferente das variáveis de membros gerais. Quando a variável Threadlocal é usada por vários threads, cada encadeamento pode obter apenas uma cópia da variável. Esta é uma descrição na API Java. Ao ler o código -fonte da API, descobri que não é uma cópia. Qual é o conceito de uma cópia? Clones? Ou outra coisa, muito vaga.
Para ser preciso, o registro (mapa <thread, t>) dentro da variável do tipo Threadlocal mudou, mas a variável do tipo Threadlocal em si é realmente uma, e essa é a essência!
Aqui está um exemplo:
1. Exemplos padrão
A classe MythreadLocal é definida e seu objeto TLT é criado e é usado por quatro threads. Como resultado, as variáveis TLT dos quatro threads não compartilham. O segundo é usar o seu próprio, o que mostra que os quatro threads usam uma cópia do TLT (clone).
/*** Use threadlocal classe*/public class MythreadLocal {// Defina uma variável Threadlocal para salvar ou Inteiro Data Inteiro Private ThreadLocal <Teger> tl = new Threadlocal <Teger> () {@Override Protected integer InitialVealue () {Return 0; }}; Public Integer GetNextNum () {// Obtenha o valor de TL e adicione 1 e atualize o valor de T1 tl.set (tl.get () + 1); retornar tl.get (); }} / *** Tópico de teste*/ classe pública testthread estende thread {private mythreadlocal tlt = new mythreadlocal (); public testthread (mythreadlocal tlt) {this.tlt = tlt; } @Override public void run () {for (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). GetName () + "/t" + tlt.getNextNum ()); }}} / *** Teste ThreadLocal*/ Public class Test {public static void main (string [] args) {mythreadlocal tlt = new mythreadLocal (); Thread t1 = new TestThread (TLT); Thread T2 = new TestThread (TLT); Thread t3 = new TestThread (TLT); Thread t4 = new TestThread (TLT); t1.start (); t2.start (); t3.start (); t4.start (); }}
Pode -se observar que os três threads são numerados de forma independente e não se afetam:
Thread-0 1 Thread-1 1 Thread-0 2 Thread-1 2 Thread-0 3 Thread-1 3 Thread-2 1 Thread-3 1 Thread-2 2 Thread-3 2 Thread-2 3 Thread-3 3 Processo acabado com o código de saída 0
O objeto TLT é um, e o objeto TL sem sentido também é um, porque o relacionamento de combinação é individual. No entanto, à medida que o número de encadeamentos aumenta, muitos objetos inteiros serão criados. É que o número inteiro e o int já são comuns. Portanto, não consigo sentir as propriedades do objeto de inteiro.
2. Não use Threadlocal
Se você não usa threadlocal, só precisa redefinir a classe MythreadLocal como:
/ *** Use threadlocal classe*/ public class mythreadlocal {private integer t1 = 0; public integer getNextNum () {return t1 = t1+1; } // Defina uma variável ThreadLocal para salvar dados int ou inteiros // private ThreadLocal <Teger> tl = new Threadlocal <Teger> () {// @Override // Inteiro protegido InitialValue () {// Return 0; //} //}; // // Public Integer getNextNum () {// // obtém o valor de TL e adicione 1 e atualize o valor de t1 // tl.set (tl.get () + 1); // retorna tl.get (); //}}
Em seguida, execute o teste:
Thread-2 1 Thread-2 2 Thread-1 4 Thread-1 6 Thread-3 3 Thread-3 9 Thread-3 10 Thread-1 8 Thread-0 7 Thread-0 11 Thread-0 12 Thread-2 5 Processo acabado com código de saída 0
A partir daqui, podemos ver que os quatro threads compartilham a variável TLT e cada thread modifica diretamente as propriedades do TLT.
3. Realize Threadlocal sozinho
pacote com.lavasoft.test2; importar java.util.Collections; importar java.util.hashmap; importar java.util.map; /*** Use threadlocal classe*/public class MythreadLocal {// Defina uma variável Threadlocal para salvar ou inteiro dados inteiros privados com.lavasoft.test2.threadlocal <pregher> tl = new com.lavasoft.test2.ThreadLocal <Integer> () { @@override protetorh }}; Public Integer GetNextNum () {// Obtenha o valor de TL e adicione 1 e atualize o valor de T1 tl.set (tl.get () + 1); retornar tl.get (); }} classe ThreadLocal <T> {mapa privado <thread, t> map = collection.synchronizedmap (novo hashmap <thread, t> ()); public threadlocal () {} protegido t InitialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containsKey (t)) {obj = inicialValue (); map.put (t, obj); } retornar obj; } public void set (valor t) {map.put (thread.currentThread (), valor); } public void remover () {map.remove (thread.currentThread ()); }}
Execute o teste:
Thread-0 1 Thread-0 2 Thread-0 3 Thread-2 1 Thread-2 2 Thread-3 1 Thread-2 3 Thread-3 2 Thread 1 1 Thread-3 3 Thread-1 2 Thread-1 3 Processo acabado com o código de saída 0
Surpreendentemente, esta versão imitadora do Threadlocal também funciona bem, implementando a função do Threadlocal na API Java.
4. Veja a essência através dos fenômenos
De fato, do ponto de vista do programa, a variável TLT é realmente uma, sem dúvida. Mas por que os números impressos não se afetam?
É por usar o número inteiro? -----não.
O motivo é: protegido t InitialValue () e get (), porque quando cada thread chama Get (), ele o criará se não existir no mapa. Quando é chamado, uma nova variável é criada com o tipo T. Toda vez que eles são criados recentemente, é claro, cada um os usa sem nenhum efeito um sobre o outro.
Para ver claramente a essência, substitua o número inteiro e reescreva algumas classes:
pacote com.lavasoft.test2; importar java.util.Collections; importar java.util.hashmap; importar java.util.map; /*** Use a classe Threadlocal*/public class mythreadlocal {// Defina uma variável Threadlocal para salvar dados int ou inteiros // private ThreadLocal <i Bean> tl = new Threadlocal <Lean> () {Private com.lavasoft.test2.Threadlocal <Lean> TLE.L.L.LaVAS.Lavasoft.Test2.Threadlocal <Lean> TLE.L.LA.LAVAS COM.Lavasoft.Test2.Threadlocal <Bean> @Override Protected Bean InitialValue () {return New Bean (); }}; @Override public string tostring () {return "mythreadlocal {" + "tl =" + tl + '}'; } public bean getBean () {return tl.get (); }} classe ThreadLocal <T> {mapa privado <thread, t> map = collection.synchronizedmap (novo hashmap <thread, t> ()); public threadlocal () {} protegido t InitialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containsKey (t)) {obj = inicialValue (); map.put (t, obj); } retornar obj; } public void set (valor t) {map.put (thread.currentThread (), valor); } public void remover () {map.remove (thread.currentThread ()); }} pacote com.lavasoft.test2; / ** * Teste Bean */ Public Class Bean {private String id = "0"; Nome da string privada = "nenhum"; public bean () {} public bean (string id, nome da string) {this.id = id; this.name = nome; } public string getId () {return id; } public void setId (string id) {this.id = id; } public string getName () {return name; } public void setName (nome da string) {this.name = name; } public String showInfo () {return "Bean {" + "id = '" + id +'/'' + ", name = '" + name +'/'' + '}'; }} pacote com.lavasoft.test2; / *** Tópico de teste*/ classe pública testthread estende thread {private mythreadlocal tlt = new mythreadlocal (); public testthread (mythreadlocal tlt) {this.tlt = tlt; } @Override public void run () {System.out.println (">>>>:" + tlt); para (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). getName ()+"/t"+tlt.getBean ()+"/t"+tlt.getBean (). showinfo ()); }}}
Em seguida, execute o teste:
>>>>>: mythreadlocal {tl=com.lavasoft.test2.mythreadlocal$1@1de3f2d} >>>>>: mythreadlocal {tl=com.lavasoft.test2.mythreadlocal$1@1de3f2d} >>>>>:MyThreadLocal{tl=com.lavasoft.test2.Bean@291aff Bean{id='0', name='none'} Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'} Thread-3 com.lavasoft.test2.Bean@186db54 Bean {id = '0', name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = 'nenhum'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = '}} Bean {id = '0', nome = 'none'} thread-0 com.lavasoft.test2.bean@291afaf bean {id = '0', name = 'nenhum'} thread-3 com.lavasoft.test2.bean@186db54 bean {id = '0', '' '} Bean {id = '0', name = 'none'} thread-1 com.lavasoft.test2.bean@291afaf bean {id = '0', nome = 'none'} thread-0 com.lavasoft.test2.bean@291aff bean {id = '0', 'NONE'}-0. Bean {id = '0', name = 'nenhum'} thread-1 com.lavasoft.test2.bean@291afaf bean {id = '0', nome = 'nenhum'} processo terminado com o código de saída 0
Fica claro a partir dos resultados da impressão que o objeto TLT do mythreadlocal é realmente um, e o objeto TL do Threadlocal no objeto TLT também é um. No entanto, quando o T1T for usado para cada encadeamento, o thread recriará o objeto Bean e o adicionará ao mapa Threadlocal para uso.
Vários mal -entendidos sobre Threadlocal:
1. Threadlocal é uma implementação de threads java
O Threadlocal está realmente relacionado aos threads java, mas não é uma implementação dos threads java, é usado apenas para manter variáveis locais. Para cada thread, ele fornece sua própria versão variável, principalmente para evitar conflitos de encadeamento, e cada thread mantém sua própria versão. Seja independente um do outro, e a modificação não afetará um ao outro.
2. Threadlocal é relativo a cada sessão
Threadlocal, como o nome indica, é destinado a threads. Na programação da Web Java, cada usuário tem seu próprio identificador de sessão do início ao final da sessão. Mas Threadlocal não está na camada de sessão. De fato, o Threadlocal é independente da sessão do usuário. É um comportamento do lado do servidor. Sempre que um servidor gera um novo thread, ele mantém seu próprio threadlocal.
Em relação a esse mal -entendido, acredito pessoalmente que deve ser o resultado do teste local do desenvolvedor com base em alguns servidores de aplicativos. Como todos sabemos, os servidores de aplicativos gerais mantêm um conjunto de pools de threads, ou seja, para cada acesso, um novo thread não gera necessariamente. Em vez disso, tenho um pool de cache de threads. Para acesso, primeiro encontre os threads existentes no pool de cache. Se eles usaram tudo, um novo thread será gerado.
Portanto, como o desenvolvedor é geralmente o único que está testando a si mesmo, a carga do servidor é muito pequena, o que leva ao compartilhamento do mesmo tópico toda vez que o acesso é, resultando no mal -entendido: cada sessão tem um threadlocal
3. Threadlocal é relativo a cada encadeamento. Cada vez que o usuário acessa, haverá um novo threadlocal.
Teoricamente, o ThreadLocal é realmente relativo a cada encadeamento, cada encadeamento terá seu próprio threadlocal. Mas, como mencionado acima, os servidores de aplicativos gerais mantêm um conjunto de pools de threads. Portanto, usuários diferentes podem receber o mesmo thread. Portanto, ao fazer o Headlocal, você precisa ter cuidado para evitar o cache das variáveis de threadlocal, fazendo com que outros threads acessem as variáveis de rosca
4. Para cada acesso ao usuário, o ThreadLocal pode ser usado várias vezes.
Pode-se dizer que o Threadlocal é uma faca de dois gumes e pode ter resultados muito bons se usados. No entanto, se o Threadlocal não for bem usado, será o mesmo que as variáveis globais. O código não pode ser reutilizado e não pode ser testado de forma independente. Porque algumas classes que poderiam ter sido reutilizadas agora confiam na variável Threadlocal. Se não houver threadlocal, essas classes ficam indisponíveis. Pessoalmente, acho que o Threadlocal é bem usado e vale a pena se referir a
1. Armazene o usuário da sessão atual: Quake Want Jert
2. Armazene algumas variáveis de contexto, como o ActionContext da Webwork
3. Sessões de loja, como sessões de hibernação de primavera