Primeiro, vamos falar sobre o conhecimento conceitual relacionado a aplicativos e processos em Java e depois explicar como criar threads e como criar processos. Aqui está o esboço do diretório deste artigo:
1.Concets relacionados a aplicações e processos em Java
2. Como criar tópicos em java
3.Como criar um processo em Java
1.Concets relacionados a aplicações e processos em Java
Em Java, um aplicativo corresponde a uma instância da JVM (também chamada de processo JVM), e o nome padrão é java.exe ou javaw.exe (pode ser visualizado através do gerenciador de tarefas no Windows). O Java adota um modelo de programação de thread único, ou seja, se não criarmos ativamente threads em nosso próprio programa, criaremos apenas um thread, que geralmente é chamado de thread principal. Mas esteja ciente de que, embora exista apenas um thread para executar tarefas não significa que exista apenas um thread na JVM. Ao criar uma instância da JVM, muitos outros threads serão criados (como threads de coletor de lixo).
Como o Java adota um modelo de programação de thread único, ao programar a interface do usuário, você deve prestar atenção à colocação de operações demoradas no encadeamento filho para evitar bloquear o encadeamento principal (ao programar a interface do usuário, o encadeamento principal é o encadeamento da interface do usuário, usado para lidar com eventos de interação do usuário).
2. Como criar tópicos em java
Se você deseja criar um thread em Java, geralmente existem duas maneiras: 1) herdar a classe Thread; 2) Implementar a interface executável.
1. Herdar a classe de threads
Se você herdar a classe Thread, deverá substituir o método de execução e definir as tarefas que precisam ser executadas no método de execução.
classe Mythread estende o thread {private static int num = 0; public mythread () {num ++; } @Override public void run () {System.out.println ("criado ativamente"+num+"threads"); }}Depois de criar sua própria classe de threads, você pode criar um objeto de encadeamento e iniciar o thread através do método START (). Observe que ele não é chamado de método run () para iniciar o thread. O método RUN define apenas as tarefas que precisam ser executadas. Se o método de execução for chamado, é equivalente a executar o método de execução no encadeamento principal, que não é diferente das chamadas de método comuns. No momento, um novo thread não será criado para executar as tarefas definidas.
public class Test {public static void main (string [] args) {mythread thread = new mythread (); thread.start (); }} classe mythread estende thread {private static int num = 0; public mythread () {num ++; } @Override public void run () {System.out.println ("criado ativamente"+num+"threads"); }}No código acima, chamando o método START (), um novo thread será criado. Para distinguir a diferença entre as chamadas do método start () e executar (), consulte o exemplo a seguir:
classe pública teste {public static void main (string [] args) {System.out.println ("ID do thread principal:"+Thread.currentThread (). getId ()); Mythread Thread1 = new Mythread ("Thread1"); Thread1.start (); Mythread thread2 = new mythread ("thread2"); Thread2.run (); }} classe mythread estende thread {private string name; public mythread (nome da string) {this.name = name; } @Override public void run () {System.out.println ("nome:"+nome+"ID do thread da criança:"+Thread.currentThread (). GetId ()); }}Resultados em execução:
A partir dos resultados da saída, as seguintes conclusões podem ser tiradas:
1) Os IDs do thread de Thread1 e Thread2 são diferentes, e o Thread2 e o ID do thread principal são os mesmos, o que significa que a chamada do método de execução não criará um novo thread, mas executará diretamente o método de execução no encadeamento principal, que não é diferente das chamadas de método comuns;
2) Embora a chamada do método inicial do Thread1 seja chamada antes do método Run do Thread2, as informações sobre a chamada do método de execução do Thread2 são emitidas primeiro, indicando que o processo de criação de um novo encadeamento não bloqueará a execução subsequente do encadeamento principal.
2. Implemente a interface executável
Além de herdar a classe Thread, a criação de threads no Java também pode implementar funções semelhantes implementando a interface executável. A implementação da interface executável deve substituir seu método de execução.
Aqui está um exemplo:
classe pública teste {public static void main (string [] args) {System.out.println ("ID do thread principal:"+Thread.currentThread (). getId ()); MyRunnable runnable = new MyRunnable (); Thread Thread = novo thread (executável); thread.start (); }} classe myRunnable implementa runnable {public myRunnable () {} @Override public void run () {System.out.println ("Subthread ID:"+Thread.currentThread (). getId ()); }}Runnable significa "tarefa" em chinês. Como o nome sugere, ao implementar a interface executável, definimos uma subtarefa e depois entregamos a subtarefa ao encadeamento para executar. Observe que esse método deve usar o Runnable como um parâmetro para a classe Thread e, em seguida, crie um novo thread para executar a subtarefa através do método de início do thread. Se o método de execução do Runnable for chamado, um novo thread não será criado e não haverá diferença entre essa chamada de método comum.
De fato, se você observar o código -fonte da implementação da classe Thread, descobrirá que a classe Thread implementa a interface executável.
Em Java, esses dois métodos podem ser usados para criar threads para executar subtarefas. O método específico a ser escolhido depende de suas necessidades. Se você herdar diretamente a classe Thread, pode parecer mais concisa do que implementar a interface executável. No entanto, como o Java apenas permite a herança única, se uma classe personalizada precisar herdar outras classes, você pode optar apenas por implementar a interface executável.
3.Como criar um processo em Java
Em Java, existem duas maneiras de criar processos, envolvendo um total de 5 classes principais.
O primeiro método é criar um processo através do método de execução.exec (), e o segundo método é criar um processo através do método de início do ProcessBuilder. Vamos falar sobre as diferenças e conexões entre esses dois métodos.
A primeira coisa que quero falar é a classe de processo. A classe de processo é uma classe abstrata. Existem principalmente vários métodos abstratos. Você pode aprender isso observando o código -fonte da classe de processo:
Localizado no caminho java.lang.process:
classe pública teste {public static void main (string [] args) {System.out.println ("ID do thread principal:"+Thread.currentThread (). getId ()); MyRunnable runnable = new MyRunnable (); Thread Thread = novo thread (executável); thread.start (); }} classe myRunnable implementa runnable {public myRunnable () {} @Override public void run () {System.out.println ("Subthread ID:"+Thread.currentThread (). getId ()); }}1) Crie um processo através do ProcessBuilder
O ProcessBuilder é uma classe final que possui dois construtores:
Public Final Class ProcessBuilder {Private List <String> Command; diretório de arquivos privado; mapa privado <string, string> ambiente; RedirecterRorStream privados booleanos; public processBuilder (list <string> command) {if (command == null) lança new nullPointerException (); this.Command = Command; } public processBuilder (string ... comando) {this.Command = new ArrayList <String> (command.length); para (string arg: comando) this.command.add (arg); } ......}O construtor passa parâmetros de comando do processo que precisam ser criados. O primeiro construtor coloca os parâmetros de comando na lista e os passa na forma de uma sequência indefinidamente longa.
Então, vamos continuar olhando para baixo. Como mencionado anteriormente, criamos um novo processo através do método inicial do ProcessBuilder. Vamos dar uma olhada no que exatamente é feito no método de início. A seguir, é apresentado o código -fonte de implementação específico do método inicial:
Public Process start () lança ioexception {// deve se converter para a matriz primeiro-uma lista maliciosa e suprida pelo usuário // pode tentar circundar a verificação de segurança.string [] cmDarray = command.toarray (new string [command.size ()]); para (string: cmDarray) se (arg == Null) lança ()); Prog de esvaziamento = cmDarray [0]; SecurityManager Security = System.GetSecurityManager (); if (Security! = NULL) Security.ChecKeC (Prog); String dir = diretório == nulo? null: diretório.toString (); tente {return processimpl.start (cmDarray, ambiente, dir, redirecterRorStream);} catch (ioexception e) {// é muito mais fácil para nós criar uma mensagem de alta qualidade // mensagem do que o código C de baixo nível que achou o problema. Jogue a nova ioexception ("não é possível executar o programa /" " + prog +" /"" " + (dir == null?" ":" (no diretório /"" " + dir +" /")") + ":" + e.getMessage (), e);}}}Este método retorna um objeto de processo. A primeira parte do método é equivalente a definir alguns parâmetros com base nos parâmetros de comando e no diretório de trabalho definido. O mais importante é uma frase no bloco de declaração de tentativa:
retornar processimpl.start (cmDarray, ambiente, dir, redirecterRorsTream);
Esta é a frase que realmente cria o processo. Observe que o método inicial da classe Processimpl é chamado. Aqui podemos saber que o início deve ser um método estático. Então, que tipo de processimpl é? Esta classe também está localizada no caminho java.lang.processimpl. Vamos dar uma olhada na implementação específica desta classe:
O ProcessiMPL também é uma classe final, que herda a classe de processo:
final class ProcessImpl extends Process { // System-dependent portion of ProcessBuilder.start() static Process start(String cmdarray[], java.util.Map<String,String> environment, String dir, boolean redirectErrorStream) throws IOException { String envblock = ProcessEnvironment.toEnvironmentBlock(environment); devolver novo ProcessiMPL (CMDARRAY, PHIRBLOCK, DIR, RedirecterRorStream); } ....}Esta é a implementação específica do método inicial da classe ProcessiMPL. De fato, esta frase é usada para criar um objeto ProcessiMPL:
devolver novo ProcessiMPL (CMDARRAY, PHIRBLOCK, DIR, RedirecterRorStream);
No ProcessiMPL, vários métodos abstratos na classe de processo são implementados na implementação concreta.
De fato, um objeto ProcessiMPL é criado através do método inicial do ProcessBuilder.
Vamos dar uma olhada no exemplo de usar o ProcessBuilder para criar um processo. Por exemplo, se eu quiser iniciar um processo através do ProcessBuilder para abrir o CMD e obter informações de endereço IP, posso escrevê -las assim:
public class Test {public static void main (string [] args) lança IoException {ProcessBuilder PB = new ProcessBuilder ("cmd", "/c", "ipconfig/all"); Processo de processo = pb.start (); Scanner scanner = new scanner (process.getInputStream ()); while (scanner.hasNextLine ()) {System.out.println (scanner.NextLine ()); } scanner.close (); }}A primeira etapa é a mais crítica, que é passar na sequência de comando para o construtor ProcessBuilder. De um modo geral, cada comando independente na string é usado como um parâmetro separado, mas também pode ser colocado na lista em ordem e transmitido.
Quanto a muitos outros usos específicos, não vou elaborar aqui, como definir variáveis de ambiente de processo e diretórios de trabalho através do método e diretório do ProcessBuilder (diretório de arquivos). Amigos interessados podem ver os documentos da API relevantes.
2) Crie um processo através do método executivo do tempo de execução
Primeiro, vamos dar uma olhada na implementação específica da classe de tempo de execução e do método EXEC. O tempo de execução, como o nome sugere, significa executar, representa a instância da máquina virtual em que o processo atual está localizado.
Como qualquer processo será executado apenas em uma instância da máquina virtual, um modo singleton é usado no tempo de execução, ou seja, apenas uma instância da máquina virtual será gerada:
public class Runtime {private Static Runtime CurrentRuntime = new RunTime (); /*** Retorna o objeto de tempo de execução associado ao aplicativo Java atual. * A maioria dos métodos de classe <Code> Runtime </code> são métodos de instância * e deve ser chamado em relação ao objeto de tempo de execução atual. * * @return the <code> Runtime </code> Objeto associado ao aplicativo atual * java. */ public static Runtime getRuntime () {return CurrentRuntime; } / ** Não deixe mais ninguém instanciar esta classe* / Private RunTime () {} ...}A partir daqui, podemos ver que, como o construtor da aula de tempo de execução é privado, só podemos obter a instância de tempo de execução através do GetRuntime. Em seguida, vamos dar uma olhada na implementação do método EXEC. Existem várias implementações diferentes de sobrecarga do EXEC no tempo de execução, mas o final da execução é esta versão do método EXEC:
Public Process Exec (String [] CMDARRAY, String [] Envp, File Dir) lança ioexception {return New ProcessBuilder (cmDarray) .Environment (ENVP) .Directory (dir) .start (); }Pode -se descobrir que, de fato, se o processo for criado através do executivo da classe de tempo de execução, ele será criado através do método de início da classe ProcessBuilder.
Vamos dar uma olhada em um exemplo para ver como criar um processo através do executivo do Runtime, ou pelo exemplo anterior, ligue para o CMD para obter informações de endereço IP:
public class Test {public static void main (string [] args) lança IoException {String cmd = "cmd"+"/c"+"ipconfig/all"; Process Process = RunTime.GetRuntime (). Exec (CMD); Scanner scanner = new scanner (process.getInputStream ()); while (scanner.hasNextLine ()) {System.out.println (scanner.NextLine ()); } scanner.close (); }}Deve-se notar que o método EXEC não suporta parâmetros de comprimento indefinido (o ProcessBuilder suporta parâmetros de comprimento indefinido), para que os parâmetros de comando devam ser emendas primeiro antes de passá-los.
Vou falar sobre como criar threads e processos em Java por enquanto. Amigos interessados podem se referir a informações relevantes.