Los hilos a menudo están involucrados en el trabajo. Por ejemplo, algunas tareas a menudo se entregan a hilos para la ejecución asincrónica. O el programa del servidor establece una tarea de procesamiento de subprocesos separada para cada solicitud. Más allá de los hilos, como la conexión de la base de datos que utilizamos. Estas operaciones de creación, destrucción o apertura y cierre tienen un gran impacto en el rendimiento del sistema. Por lo tanto, se resalta el uso de "piscina".
1. ¿Por qué usar el grupo de hilos
En la implementación descrita en la Sección 3.6.1, se asigna un nuevo hilo de trabajadores a cada cliente. Cuando el hilo del trabajador se comunica con el cliente, el hilo se destruye. Este método de implementación tiene las siguientes deficiencias:
• La sobrecarga de la creación y destrucción del servidor (incluido el tiempo y los recursos del sistema) es muy alta. No es necesario explicar este elemento, puede verificar el "proceso de creación de hilos". Además del trabajo realizado por la misma máquina, también necesitamos instanciar y comenzar, lo que requiere la ocupación de los recursos de la pila.
• Además de la sobrecarga de la creación y la destrucción de los hilos, los hilos activos también consumen recursos del sistema. Esto debería ser un consumo de recursos de pila. También se considera adivinar el número de conexiones de bases de datos.
• Si el número de subprocesos es fijo y cada subproceso tiene un ciclo de declaración largo, entonces la conmutación de subprocesos también es relativamente fija. Los diferentes sistemas operativos tienen diferentes ciclos de conmutación, generalmente alrededor de 20 ms. El interruptor mencionado aquí es transferir los derechos de uso de la CPU entre los subprocesos bajo la programación de JVM y el sistema operativo subyacente. Si los hilos se crean y destruyen con frecuencia, los hilos se cambiarán con frecuencia, porque después de que se destruye un hilo, el derecho de usar se debe dar al hilo listo, para que el hilo pueda tener la oportunidad de ejecutar. En este caso, la conmutación entre hilos no sigue el ciclo de conmutación fijo del sistema, y la sobrecarga de las roscas de conmutación es incluso mayor que la sobrecarga de la creación y la destrucción.
Relativamente hablando, utilizando grupos de subprocesos, algunos hilos se crean pre-creados, que constantemente eliminan las tareas de la cola de trabajo y luego ejecutan la tarea. Cuando el hilo del trabajador completa una tarea, continúa ejecutando otra tarea en la cola de trabajo. Las ventajas son las siguientes:
• Reduce el número de creación y destrucción, y cada hilo de trabajadores se puede reutilizar todo el tiempo y puede realizar múltiples tareas.
• El número de subprocesos en el grupo de subprocesos se puede ajustar fácilmente de acuerdo con la capacidad de carga del sistema para evitar bloqueos del sistema debido a los recursos excesivos del sistema.
2. Implementación simple de Pool de hilos
A continuación se muestra un grupo de hilos simple escrito por mí mismo, que también se extrajo directamente del libro de programación de la red Java
Hilo de paquete; import java.util.linkedList;/*** Implementación del grupo de subprocesos, según la longitud, la longitud máxima y la longitud de la cola del grupo de subprocesos regulares, podemos aumentar el número de implementaciones* @author Han*/public class MyThreadPool extiende Threadgroup {// número CPU --- runtime.getRunTime (). // si cerrar el booleano privado istRosed = false; // cola private LinkedList <Runnable> WorkQueue; // ID de grupo de hilos ID privado int threadpoolid; private int threadid; public MyThreadPool (int PoolSize) {super ("mythreadpool".+threadpoolid); ThreadPoolID ++; setdaemon (verdadero); WorkQueue = new LinkedList <Runnable> (); for (int i = 0; i <proupsize; i ++) {new WorkThread (). Start (); }} // Aquí puede cambiar a concurrentLinkedQueue para evitar la eficiencia del uso de ejecución sincronizada pública sincronizada (tarea runnable) {if (isClosed) {lanzar nueva IllegalStateException ("El grupo de conexión se ha cerrado ..."); } else {workqueue.add (tarea); notificar(); }} protegido sincronizado runnable getTask () lanza interruptedException {while (workqueue.size () == 0) {if (isClosed) {return null; } esperar(); } return workqueue.removeFirst (); } public sincronizado void Close () {if (! isClosed) {isClosed = true; WorkQueue.Clear (); interrumpir(); }} public void Join () {SynChronized (this) {isClosed = true; notifyall (); } Hilo [] hilos = new Thread [activeCount ()]; int count = enumerate (hilos); for (int i = 0; i <count; i ++) {try {hilts [i] .Join (); } catch (Exception e) {}}} class WorkThread extiende el hilo {public WorkThread () {super (myThreadPool.this, "WorkThread"+(ThreadID ++)); System.out.println ("Crear ..."); } @Override public void run () {while (! Isinterrupted ()) {system.out.println ("run .."); Tarea runnable = null; intente {// Esta es una tarea de método de bloqueo = getTask (); } catch (excepción e) {} if (tarea! = null) {task.run (); } else {break; }}}}}}Este grupo de hilos define principalmente una cola de trabajo y algunos hilos pre-creados. Mientras se llame al método de ejecución, puede enviar tareas al hilo.
Cuando no hay tarea, el hilo posterior se bloqueará en GetTask () hasta que entre una nueva tarea y se despierta.
Tanto unirse como el cierre se pueden usar para cerrar el grupo de hilos. La diferencia es que Join completará las tareas en la cola, mientras que Close eliminará inmediatamente la cola e interrumpirá todos los hilos de los trabajadores. La interrupción () en Close () es equivalente a llamar a la interrupción respectiva () que contiene hilos infantiles en Threadgroup. Por lo tanto, cuando un hilo está esperando o duerme, se lanzará una interrupción.
La clase de prueba es la siguiente:
public class testMyThreadPool {public static void main (string [] args) lanza interruptedException {myThreadPool Pool = new MyThreadPool (3); for (int i = 0; i <10; i ++) {pisceS.Execute (new runnable () {@Override public void run () {try {thread.sleep (1000);} catch (interruptedException e) {} system.out.println ("Working ...");}}); } piscina.Join (); //pool.close (); }}3. El grupo de hilos proporcionado por la biblioteca de clases JDK
Java proporciona una buena implementación del grupo de hilos, que es más robusta y eficiente que nuestra propia implementación, y también tiene funciones más poderosas.
El diagrama de clases es el siguiente:
Las personas mayores ya han dado una buena explicación sobre este tipo de grupo de hilos. Cualquier grupo de hilos de Java en Baidu tiene ejemplos y tutoriales muy detallados escritos, por lo que no los repetiré aquí.
4. Piscina de hilo de inyección de primavera
Cuando usamos el marco de Spring, si usamos los métodos proporcionados por Java para crear un grupo de subprocesos, es muy inconveniente administrar en aplicaciones de múltiples subprocesos y no se ajusta a nuestra idea de usar Spring. (Aunque la primavera se puede inyectar mediante métodos estáticos)
De hecho, Spring en sí también proporciona una buena implementación de grupos de subprocesos. Esta clase se llama ThreadpoolTaskExecutor.
La configuración en primavera es la siguiente:
<bean id = "ejecutorservice"> <propiedad name = "corePoolSize" value = "$ {threadpool.corePoolSize}" /> <!-Número mínimo de subprocesos mantenidos por subprocesos-> <Property name = "KeepAliveSeconds" Value = "$ {ThreadPool.keepaliveSeconds}" /> <!-Tiempo libre permitido para hilos de mantenimiento: hilos de hilos-hilos de hilos-hilos de mantenimiento-> name = "maxpoolSize" value = "$ {threadpool.maxpoolsize}" /> <!-Número máximo de subprocesos mantenidos por el grupo de hilos-> <propiedad name = "QueueCapacity" value = "$ {threadpool.queueCapacity}" /> <!-El cola de búfer utilizado por Thread Pool-> < /bean>5. Notas sobre el uso de piscinas de hilos
•Punto muerto
Cualquier programa multiproceso tiene el riesgo de matrimonio. El caso más simple es que dos subprocesos AB, A contiene bloqueo 1, el bloqueo de solicitud 2, B contiene el bloqueo 2 y el bloqueo de solicitud 1. (Esta situación también aparecerá en el bloqueo exclusivo de MySQL y la base de datos informará directamente un mensaje de error). Hay otro punto muerto en el grupo de subprocesos: suponiendo que todos los hilos de los trabajadores en el grupo de subprocesos estén bloqueados al ejecutar sus respectivas tareas, y están esperando el resultado de la ejecución de una determinada tarea A. La tarea A está en la cola y no se puede ejecutar porque no hay hilos inactivos. De esta manera, todos los recursos del grupo de subprocesos serán bloqueados y se generarán estancamientos.
• Recursos del sistema insuficientes
Si el número de subprocesos en el grupo de subprocesos es muy grande, estos hilos consumirán una gran cantidad de recursos, incluida la memoria y otros recursos del sistema, lo que afecta seriamente el rendimiento del sistema.
• Error concurrente
La cola de trabajo del grupo de subprocesos se basa en los métodos Wait () y notificar () para permitir que el trabajador obtenga tareas de manera oportuna, pero estos dos métodos son difíciles de usar. Si el código es incorrecto, se pueden perder notificaciones, lo que hace que el hilo del trabajador permanezca inactivo, ignorando las tareas que deben procesarse en la cola de trabajo. Porque es mejor usar algunas piscinas de hilos más maduras.
• Fuga de hilos
Un riesgo grave de usar grupos de subprocesos es la fuga de hilos. Para los grupos de subprocesos con un número fijo de hilos de trabajadores, si el hilo del trabajador lanza una Error o error RuntimeException al ejecutar una tarea, y estas excepciones o errores no se capturan, el hilo del trabajador termina anormalmente, lo que hace que el grupo de subprocesos pierda un hilo permanentemente. (Esto es muy interesante)
Otra situación es que el hilo del trabajador está bloqueado al ejecutar una tarea. Si está esperando los datos de entrada del usuario, pero el usuario no ingresa datos, lo que resulta en que el hilo se bloquee todo el tiempo. Tal hilo de trabajador está solo en nombre, y en realidad no realiza ninguna tarea. Si todos los hilos en el grupo de subprocesos están en este estado, el grupo de subprocesos no puede agregar nuevas tareas.
• sobrecarga de tareas
Cuando hay una gran cantidad de tareas en cola para ejecutarse en la cola de hilo de trabajadores, estas tareas en sí mismas pueden consumir demasiados recursos del sistema y causar escasez de recursos.
Para resumir, cuando se usa piscinas de subprocesos, se deben seguir los siguientes principios:
1. Si la Tarea A necesita esperar el resultado de la ejecución de la Tarea B sincrónicamente durante la ejecución, entonces la Tarea A no es adecuada para agregarse a la cola de trabajo del grupo de subprocesos. Si necesita esperar a que otras tareas ejecuten resultados como la tarea A que se agregará a la cola, puede causar un punto muerto
2. Si se puede bloquear una tarea y se bloquea durante mucho tiempo, se debe establecer el tiempo de tiempo de espera para evitar el bloqueo permanente del hilo del trabajador y causar fugas de hilo. En el programa del servidor, cuando un hilo está esperando que el cliente se conecte o espere los datos enviados por el cliente, puede causar bloqueo. Puede establecer el tiempo de las siguientes maneras:
Llame al método SetSotimeOut de Serversocket para establecer el tiempo de tiempo de espera para esperar a que el cliente se conecte.
Para cada socket conectado al cliente, llame al método SetSotimeOut del socket para establecer el tiempo de tiempo de espera esperando que el cliente envíe datos.
3. Comprenda las características de la tarea y analice si la tarea realiza operaciones que a menudo bloquean las operaciones de IO o realizan operaciones que no bloqueen. El primero ocupa CPU intermitentemente, mientras que el segundo tiene una mayor tasa de utilización. ¿Cuánto tiempo se tarda en completar una tarea? ¿Es una tarea a corto plazo o una tarea a largo plazo? Luego, clasifique las tareas de acuerdo con las características de la tarea y luego agregue diferentes tipos de tareas a la cola de trabajo de diferentes grupos de hilos. De esta manera, cada grupo de hilos se puede asignar y ajustar de acuerdo con las características de la tarea.
4. Cambie el tamaño de la piscina de hilo. El tamaño óptimo de un grupo de subprocesos depende principalmente de la cantidad de CPU disponibles en el sistema y las características de las tareas en la cola de trabajo. Si solo hay una cola de trabajo en un sistema con N CPU, y todas ellas son tareas de naturaleza aritmética (no bloqueo), entonces cuando el grupo de subprocesos tiene hilos de trabajadores N o n+1, el uso máximo de la CPU generalmente se obtendrá.
Si la cola de trabajo contiene tareas que realizan operaciones de IO y, a menudo, el tamaño del grupo de subprocesos excede la cantidad de CPU disponibles, porque no todos los hilos de trabajo funcionan todo el tiempo. Seleccione una tarea típica y luego estime la relación del tiempo de espera para el tiempo que realmente ocupa CPU para realizar operaciones en el proyecto que realiza esta tarea. Para un sistema con n CPU, se deben establecer aproximadamente n*(1+wt/st) los hilos para garantizar que la CPU se utilice completamente.
Por supuesto, la utilización de la CPU no es lo único que se debe considerar en el proceso de ajustar los grupos de subprocesos. A medida que aumenta el número de trabajo en el grupo de subprocesos, también se producirán restricciones de memoria u otras restricciones de recursos, como sockets, manijas de archivos abiertas o conexiones de bases de datos, etc. Es necesario asegurarse de que los recursos del sistema consumidos por Multithreads estén dentro del alcance de la resistencia del sistema.
5. Evite la sobrecarga de tareas. El servidor debe limitar el número de conexiones concurrentes de los clientes en función de la capacidad de carga del sistema. Cuando la conexión del cliente excede el valor límite, el servidor puede rechazar la conexión y hacer indicaciones amigas, o limitar la longitud de la cola.
Los anteriores varios métodos de implementación y respuestas a Java Hild Pools son todo el contenido que he compartido con usted. Espero que pueda darle una referencia y espero que pueda apoyar más a Wulin.com.