Primero, hablemos sobre el conocimiento conceptual relacionado con aplicaciones y procesos en Java, y luego expliquemos cómo crear hilos y cómo crear procesos. Aquí está el esquema del directorio de este artículo:
1. conceptos relacionados con aplicaciones y procesos en Java
2. Cómo crear hilos en Java
3. Cómo crear un proceso en Java
1. conceptos relacionados con aplicaciones y procesos en Java
En Java, una aplicación corresponde a una instancia JVM (también llamada proceso JVM), y el nombre predeterminado es Java.exe o Javaw.exe (se puede ver a través del Administrador de tareas en Windows). Java adopta un modelo de programación único, es decir, si no creamos activamente hilos en nuestro propio programa, solo crearemos un hilo, que generalmente se llama hilo principal. Pero tenga en cuenta que, aunque solo hay un hilo para realizar tareas no significa que solo haya un hilo en el JVM. Al crear una instancia de JVM, se crearán muchos otros hilos (como hilos de recolector de basura).
Dado que Java adopta un modelo de programación único, al programar la interfaz de usuario, debe prestar atención a poner operaciones que llevan mucho tiempo en el hilo infantil para evitar bloquear el hilo principal (al programar la interfaz de usuario, el hilo principal es el hilo de la interfaz de usuario, que se usa para manejar los eventos de interacción del usuario).
2. Cómo crear hilos en Java
Si desea crear un hilo en Java, generalmente hay dos formas: 1) heredar la clase de hilo; 2) Implemente la interfaz ejecutable.
1. Heredar la clase de hilo
Si hereda la clase de subprocesos, debe anular el método Ejecutar y definir las tareas que deben ejecutarse en el método Ejecutar.
clase myThread extiende hilo {private static int num = 0; public mythread () {num ++; } @Override public void run () {system.out.println ("creado activamente"+num+"hilos"); }}Después de crear su propia clase de hilo, puede crear un objeto de subproceso y luego iniciar el hilo a través del método Start (). Tenga en cuenta que no se llama el método run () para iniciar el hilo. El método de ejecución solo define las tareas que deben ejecutarse. Si se llama al método de ejecución, es equivalente a ejecutar el método Ejecutar en el hilo principal, que no es diferente de las llamadas de método ordinario. En este momento, no se creará un nuevo hilo para ejecutar las tareas definidas.
prueba de clase pública {public static void main (string [] args) {myThread Thread = new MyThread (); Thread.Start (); }} La clase myThread extiende el hilo {private static int num = 0; public mythread () {num ++; } @Override public void run () {system.out.println ("creado activamente"+num+"hilos"); }}En el código anterior, llamando al método Start (), se creará un nuevo hilo. Para distinguir la diferencia entre las llamadas del método Start () y las llamadas de método Ejecutar (), consulte el siguiente ejemplo:
Prueba de clase pública {public static void main (string [] args) {System.out.println ("ID de hilo principal:"+Thread.CurrentThread (). getId ()); MyThread Thread1 = nuevo MyThread ("Thread1"); Thread1.Start (); MyThread Thread2 = new MyThread ("Thread2"); thread2.run (); }} La clase MyThread extiende el hilo {nombre de cadena privada; public mythread (nombre de cadena) {this.name = name; } @Override public void run () {System.out.println ("Name:"+Name+"Child Thread ID:"+Thread.CurrentThread (). GetId ()); }}Resultados de ejecución:
De los resultados de la salida, se pueden extraer las siguientes conclusiones:
1) Las ID de subproceso de Thread1 y Thread2 son diferentes, y Thread2 y la ID de subproceso principal son las mismas, lo que significa que la llamada de método Ejecutar no creará un nuevo hilo, sino que ejecutará directamente el método Ejecutar en el hilo principal, que no es diferente de las llamadas de método ordinaria;
2) Aunque la llamada del método de inicio de Thread1 se llama antes del método de ejecución de Thread2, la información sobre la llamada del método Ej.
2. Implemente la interfaz ejecutable
Además de heredar la clase de subprocesos, la creación de hilos en Java también puede implementar funciones similares implementando la interfaz ejecutable. Implementación de la interfaz ejecutable debe anular su método Ejecutar.
Aquí hay un ejemplo:
Prueba de clase pública {public static void main (string [] args) {System.out.println ("ID de hilo principal:"+Thread.CurrentThread (). getId ()); Myrunnable runnable = new Myrunnable (); Thread Thread = New Thread (Runnable); Thread.Start (); }} class Myrunnable implementos runnable {public myrunnable () {} @Override public void run () {System.out.println ("Subthread ID:"+Thread.CurrentThread (). GetId ()); }}Runnable significa "tarea" en chino. Como su nombre indica, al implementar la interfaz ejecutable, definimos una subtarea y luego entregamos la subtarea para ejecutar para ejecutar. Tenga en cuenta que este método debe usar Runnable como parámetro para la clase de subprocesos, y luego crear un nuevo hilo para ejecutar la subtarea a través del método de inicio de subprocesos. Si se llama al método de ejecución de Runnable, no se creará un nuevo hilo, y no hay diferencia entre esta llamada de método ordinario.
De hecho, si observa el código fuente de implementación de la clase de subprocesos, encontrará que la clase de subprocesos implementa la interfaz ejecutable.
En Java, estos dos métodos se pueden usar para crear subprocesos para ejecutar subtareas. El método específico para elegir depende de sus necesidades. Si hereda directamente la clase de subprocesos, puede parecer más conciso que implementar la interfaz ejecutable. Sin embargo, dado que Java solo permite una herencia única, si una clase personalizada necesita heredar otras clases, solo puede optar por implementar la interfaz ejecutable.
3. Cómo crear un proceso en Java
En Java, hay dos formas de crear procesos, que involucran un total de 5 clases principales.
El primer método es crear un proceso a través del método Runtime.exec (), y el segundo método es crear un proceso a través del método de inicio de ProcessBuilder. Hablemos sobre las diferencias y conexiones entre estos dos métodos.
Lo primero de lo que quiero hablar es la clase de proceso. La clase de proceso es una clase abstracta. Hay principalmente varios métodos abstractos en él. Puede aprender esto mirando el código fuente de la clase de proceso:
Ubicado en la ruta Java.Lang.Process:
Prueba de clase pública {public static void main (string [] args) {System.out.println ("ID de hilo principal:"+Thread.CurrentThread (). getId ()); Myrunnable runnable = new Myrunnable (); Thread Thread = New Thread (Runnable); Thread.Start (); }} class Myrunnable implementos runnable {public myrunnable () {} @Override public void run () {System.out.println ("Subthread ID:"+Thread.CurrentThread (). GetId ()); }}1) Crear un proceso a través de ProcessBuilder
ProcessBuilder es una clase final que tiene dos constructores:
Public Final Class ProcessBuilder {comando de la lista privada <String>; directorio de archivos privados; mapa privado <string, string> entorno; RedirectterrorRorrorRorrorRorrorror de booleano privado; Public ProcessBuilder (list <string> command) {if (command == NULL) Throw New NULLPOInterException (); this.command = comando; } public ProcessBuilder (String ... Command) {this.command = new ArrayList <String> (Command.Length); para (string arg: command) this.command.add (arg); } ......}El constructor pasa los parámetros de comando del proceso que debe crearse. El primer constructor coloca los parámetros de comando en la lista y los pasa en forma de una cadena indefinidamente larga.
Así que sigamos mirando hacia abajo. Como se mencionó anteriormente, creamos un nuevo proceso a través del método de inicio de ProcessBuilder. Echemos un vistazo a lo que se hace exactamente en el método de inicio. El siguiente es el código fuente de implementación específico del método de inicio:
Public Process Start () lanza ioexception {// debe convertirse en matriz Embytring prog = cmdarray [0]; SecurityManager Security = System.getSecurityManager (); if (Security! = NULL) Security.checkExec (prog); Cadena dir = directorio == null? NULL: Directory.ToString (); Pruebe {return ProcessImpl.start (cmdArray, ambiente, dir, redirectterrorRtore);} catch (ioException e) {// es mucho más fácil para nosotros crear un error de alta calidad // mensaje que el código C de bajo nivel que encontró el problema. Tire nuevo IOException ("No se ejecute el programa /" " + prog +" /"" + (dir == null? "": "(en directorio /" " + dir +" /")") + ":" + e.getMessage (), e);}}Este método devuelve un objeto de proceso. La primera parte del método es equivalente a establecer algunos parámetros en función de los parámetros de comando y el directorio de trabajo establecido. Lo más importante es una oración en el bloque de instrucciones de try:
return processImpl.start (cmdArray, entorno, dir, redirectterrorRtream);
Esta es la oración que realmente crea el proceso. Tenga en cuenta que se llama al método de inicio de la clase ProcessImpl. Aquí podemos saber que el inicio debe ser un método estático. Entonces, ¿qué tipo de proceso es? Esta clase también se encuentra en la ruta Java.Lang.ProcessImpl. Echemos un vistazo a la implementación específica de esta clase:
ProcessImpl también es una clase final, que hereda la clase de proceso:
La clase final de processImpl extiende el proceso {// porción dependiente del sistema de ProcessBuUder.start () static Process Start (String cmDarray [], java.util.map <string, string> entorno, string dir, boolean redirErrorRorStream) lanza ioexception {string envblock = processEnvironment.toenvironmock (entorno); devolver nuevo ProcessImpl (CMDArray, Envblock, DIR, redirectterRorStream); } ....}Esta es la implementación específica del método de inicio de la clase ProcessImpl. De hecho, esta oración se usa para crear un objeto ProcessImpl:
devolver nuevo ProcessImpl (CMDArray, Envblock, DIR, redirectterRorStream);
En ProcessImpl, varios métodos abstractos en la clase de proceso se implementan en implementación concreta.
De hecho, se crea un objeto ProcessImpl a través del método de inicio de ProcessBuilder.
Echemos un vistazo al ejemplo de usar ProcessBuilder para crear un proceso. Por ejemplo, si quiero comenzar un proceso a través de ProcessBuilder para abrir CMD y obtener información de la dirección IP, entonces puedo escribirlo así:
Public Class Test {public static void main (string [] args) lanza ioexception {ProcessBuilder pb = new ProcessBuilder ("CMD", "/c", "ipconfig/all"); Proceso proceso = pb.start (); Scanner Scanner = New Scanner (Process.getInputStream ()); while (Scanner.hasNextLine ()) {System.out.println (Scanner.NextLine ()); } scanner.close (); }}El primer paso es el más crítico, que es pasar la cadena de comando al constructor ProcessBuilder. En términos generales, cada comando independiente en la cadena se usa como un parámetro separado, pero también se puede colocar en la lista en orden y pasar.
En cuanto a muchos otros usos específicos, no daré más detalles sobre ellos aquí, como establecer variables de entorno de proceso y directorios de trabajo a través del método de entorno de ProcessBuilder (directorio de archivos). Los amigos interesados pueden ver los documentos API relevantes.
2) Crear un proceso a través del método EXECTime de Runtime
Primero, echemos un vistazo a la implementación específica de la clase de tiempo de ejecución y el método EXEC. El tiempo de ejecución, como su nombre indica, significa ejecutar, representa la instancia de la máquina virtual donde se encuentra el proceso actual.
Dado que cualquier proceso solo se ejecutará en una instancia de máquina virtual, se utiliza un modo singleton en tiempo de ejecución, es decir, solo se generará una instancia de máquina virtual:
tiempo de ejecución de clase pública {tiempo de ejecución estático privado currentRuntime = new Runtime (); /*** Devuelve el objeto de tiempo de ejecución asociado con la aplicación Java actual. * La mayoría de los métodos de clase <code> runtime </code> son métodos de instancia * y deben invocarse con respecto al objeto de tiempo de ejecución actual. * * @return El objeto <code> runtime </code> asociado con la aplicación Java actual *. */ public static runtime getruntime () {return currentRuntime; } / ** No dejes que nadie más instancíe esta clase* / private runtime () {} ...}Desde aquí, podemos ver que, dado que el constructor de la clase de tiempo de ejecución es privado, solo podemos obtener la instancia de tiempo de ejecución a través de GetRuntime. A continuación, echemos un vistazo más de cerca a la implementación del método EXEC. Hay múltiples implementaciones de sobrecarga diferentes de EXEC en tiempo de ejecución, pero el final de la ejecución es esta versión del método EXEC:
Public Process Exec (String [] CMDArray, String [] Envp, File Dir) lanza IOException {return New ProcessBuilder (cmDarray) .environment (envp) .directory (dir) .start (); }Se puede encontrar que, de hecho, si el proceso se crea a través del EXEC de la clase de tiempo de ejecución, en última instancia se crea a través del método de inicio de la clase ProcessBuilder.
Echemos un vistazo a un ejemplo para ver cómo crear un proceso a través del ejecución de tiempo de ejecución, o el ejemplo anterior, llame a CMD para obtener información de la dirección IP:
Prueba de clase pública {public static void main (string [] args) lanza ioexception {string cmd = "cmd"+"/c"+"ipconfig/all"; Proceso proceso = runtime.getRuntime (). Exec (cmd); Scanner Scanner = New Scanner (Process.getInputStream ()); while (Scanner.hasNextLine ()) {System.out.println (Scanner.NextLine ()); } scanner.close (); }}Cabe señalar que el método EXEC no admite parámetros de longitud indefinida (ProcessBuilder admite parámetros de longitud indefinida), por lo que los parámetros de comando deben empalmarse primero antes de pasarlos.
Hablaré sobre cómo crear hilos y procesos en Java por el momento. Los amigos interesados pueden referirse a la información relevante.