1. O que é um padrão de design
Na engenharia de software, o padrão de design é uma solução proposta a vários problemas comuns (recorrentes) no design de software. Este termo foi introduzido na ciência da computação a partir do campo do projeto arquitetônico nos anos 90 por Erich Gamma e outros.
Famous 4 pessoas gangue: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (GoF)
Padrão de design: o básico do software reutilizável orientado a objetos
2. Modo Singleton
A classe de um objeto Singleton deve ter apenas uma instância. Muitas vezes, todo o sistema precisa apenas ter um objeto global, que é propício à nossa coordenação do comportamento geral do sistema.
Por exemplo: Configuração de informações globais
A implementação mais simples do modo Singleton:
public class Singleton {private singleton () {System.out.println ("Singleton Is Create"); } private estático singleton instância = new singleton (); public static singleton getInstance () {retorna instância; }} A singularidade é determinada pelo construtor privado e estático.
Desvantagens: quando uma instância é gerada é difícil de controlar
Embora saibamos que quando o singleton da classe é carregado pela primeira vez, uma instância é gerada.
Mas se houver outras propriedades nesta classe
classe pública Singleton {public static int status = 1; private singleton () {System.out.println ("Singleton Is Create"); } private estático singleton instância = new singleton (); public static singleton getInstance () {retorna instância; }} Ao usar
System.out.println (singleton.status);
Este exemplo é produzido. Talvez você não queira que esta instância seja gerada neste momento.
Se o sistema prestar atenção especial a esse problema, o método de implementação deste singleton não será muito bom.
A solução para o segundo modo Singleton:
public class Singleton {private singleton () {System.out.println ("Singleton Is Create"); } private estático singleton instance = null; public static sincronizado singleton getInstance () {if (instance == null) instância = new singleton (); instância de retorno; }} Deixe a instância ser criada apenas quando o método getInstance () for chamado e a segurança do encadeamento é garantida por meio de sincronizado.
Isso controla quando as instâncias são criadas.
Essa abordagem é típica do carregamento preguiçoso.
Mas um problema é que o desempenho terá um impacto em cenários de alta concorrência. Embora seja devolvido com apenas um julgamento, terá um impacto no caso de alta simultaneidade, terá um impacto mais ou menos porque você precisa obter a trava sincronizada.
Para ser eficiente, há um terceiro método:
public class STATICSINGLETON {private STATICSINGLETON () {System.out.println ("STATICSINGLETON IS CREATE"); } classe estática privada SingleToholder {private Static STATICSINGLETONSTETE = new STATICSINGLETON (); } public static staticsingleton getInstance () {return singletonholder.instance; }} Desde quando uma classe é carregada, sua classe interna não será carregada. Isso garante que a instância seja gerada apenas quando o GetInstance () for chamado, o tempo de geração da instância é controlado e o carregamento atrasado é alcançado.
E sincronizado é removido para melhorar o desempenho e estático é usado para garantir a singularidade.
3. Modo invariante
Depois que o estado interno de uma classe é criado, ela não mudará durante todo o período de vida.
O modo UMAnge não requer sincronização
Crie uma classe inalterada:
Public Final Class Product {// Verifique se não há Subclasse Private Final String Não; // Atributos privados não serão obtidos por outros objetos Nome da string final privada; // Garantias finais de que o atributo não será atribuído duas vezes o preço duplo privado; produto público (string no, nome da string, preço duplo) {// Ao criar um objeto, os dados devem ser especificados super (); // Porque após a criação, não pode ser modificado isso.no = não; this.name = nome; this.price = preço; } public string getNo () {return no; } public string getName () {return name; } public Double getPrice () {Return Price; }} Os casos de padrões imutáveis em Java incluem:
java.lang.string
java.lang.boolean
java.lang.byte
java.lang.Character
java.lang.double
java.lang.float
java.lang.integer
java.lang.long
java.lang.short
4. Modo futuro
A idéia principal são chamadas assíncronas
Não asíncrono:
assíncrono:
O primeiro call_return é retornado, pois a tarefa ainda não foi concluída.
Mas isso retorna é semelhante a uma ordem nas compras e você pode obter um resultado com base nesse pedido no futuro.
Portanto, esse modelo futuro significa que "futuro" pode ser obtido, o que significa que a ordem ou contrato é a "promessa" e dará o resultado no futuro.
Implementação simples do modo futuro:
O que o chamador recebe é um dados, que pode ser um Futuredata no início, porque o RealData demora a ser construída. Em algum momento, no futuro, o RealData pode ser obtido através do Futuredata.
Implementação de código:
Dados da interface pública {public String getResult (); } classe pública Futuredata implementa dados {Protected RealData realData = null; // FutureData é um booleano protegido do REALDATATA ISSOLHE = FALSE; public sincronizado void setRealData (realData realData) {if (isready) {return; } this.realData = realData; isready = true; notifyAll (); // realdata foi injetado, notifique getResult ()} public sincronizada string getResult () // aguardará a construção da construção do RealData concluir {while (! Isready) {try {wait (); // Aguarde o tempo todo para saber que o RealData está injetado} Catch (interruptEdException e) {}} retorna realdata.result; // implementado por realdata}} classe pública realdata implementa dados {resultado final da string protegida; public RealData (string para) {// A construção do RealData pode ser muito lenta e exige que o usuário aguarde muito tempo. Aqui usamos o sono para simular StringBuffer sb = new StringBuffer (); for (int i = 0; i <10; i ++) {sb.append (para); tente {// use dormir aqui em vez de um thread de operação muito lento.Sleep (100); } catch (interruptedException e) {}} resultado = sb.toString (); } public string getResult () {return resultado; }} public class Client {Public Data Solicy (Final String Querystr) {Final Futuredata Future = new Futuredata (); novo thread () {public void run () {// realData é muito lento para construir, // SO REALDATA em um thread separado realData = new RealData (Querystr); futuro.setRealData (RealData); } } }.começar(); retornar futuro; // Futuredata será retornado imediatamente}} public static void main (string [] args) {client client = new client (); // Isso será retornado imediatamente porque o que você obtém é o Futuredata em vez de dados do RealData Data = client.request ("nome"); System.out.println ("solicitação concluída"); tente {// aqui você pode usar um sono em vez de processar outras lógicas de negócios // No processo de processamento dessas lógicas de negócios, o RealData é criado, fazendo uso total do thread de tempo de espera.sleep (2000); } catch (interruptedException e) {} // use o real system.out.println ("data =" + data.getResult ()); }Também existem muitos suporte futuro no JDK:
Em seguida, use as classes e métodos fornecidos pelo JDK para implementar o código agora:
importar java.util.Concurrent.Callable; public class RealData implementa Callable <String> {private String par; public RealData (string para) {this.para = par; } @Override public String Call () lança Exceção {StringBuffer sb = new StringBuffer (); for (int i = 0; i <10; i ++) {sb.append (para); tente {thread.sleep (100); } catch (interruptedException e) {}} retorna sb.toString (); }} importar java.util.concurrent.executionException; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; importar java.util.Concurrent.futureTask; public class FutureMain {public static vaid main (string [] FutureTask <String> futuro = new FutureTask <String> (new RealData ("A")); ExecutorService Exector = executores.newfixedThreadpool (1); // Execute o FutureTask, equivalente a client.request ("A") no exemplo acima, envie uma solicitação // Ative o thread aqui para executar o RealData Call () e execute executor.submit (futuro); System.out.println ("solicitação concluída"); tente {// operações de dados adicionais ainda podem ser feitas aqui, e o sono pode ser usado em vez de processar outros threads de lógica de negócios.sleep (2000); } catch (interruptedException e) {} // equivalente a data.getResult (), obtenha o valor de retorno do método Call () // se o método Call () não for executado neste momento, ele ainda aguardará o System.out.println ("data =" + futuro.get ()); }} O que você precisa observar aqui é que o FutureTask é uma classe que tem função futura e função executável. Para que possa correr novamente e finalmente obtê -lo.
Obviamente, se os dados reais não estiverem prontos ao ligar para o futuro.get (), isso ainda causará uma situação de bloqueio até que os dados estejam prontos.
Claro que existem maneiras mais fáceis:
importar java.util.concurrent.executionException; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; importar java.util.util.Concurrent.future; public class FutureMain2 {public STATION MAIN MAIN (String [] Executores.newfixedthreadpool (1); // Execute o FutureTask, equivalente a client.request ("a") no exemplo acima, envie uma solicitação // Abra o tópico aqui para executar o RealData Call () e execute o futuro <string> futuro = executor.submit (novo realdata ("a")); System.out.println ("solicitação concluída"); tente {// operações de dados adicionais ainda podem ser feitas aqui, use o sono em vez de outros threads de processamento de lógica de negócios.sleep (2000); } Catch (interruptedException e) {} // equivalente a data.getResult (), obtenha o valor de retorno do método Call () // se o método Call () não executar no momento, System.out.println ainda estará esperando pelo sistema.out.println ("data =" + Future.get ()); }} Como o Callable tem um valor de retorno, você pode retornar diretamente o objeto futuro.
5. Produtor e consumidor
O modelo do produtor-consumidor é um modelo de design multithread clássico. Ele fornece uma boa solução para colaboração entre vários threads. No modelo produtor-consumidor, geralmente existem dois tipos de threads, a saber, vários threads produtores e vários threads de consumo. O thread do produtor é responsável por enviar solicitações de usuário, enquanto o thread do consumidor é responsável por lidar especificamente nas tarefas enviadas pelo produtor. O produtor e o consumidor se comunicam através de um buffer de memória compartilhado.
Escrevi um artigo no passado para implementar vários métodos de uso do Java para implementar produtores e consumidores, para que não o explique aqui.