Multithreading en la programación concurrente de Java

El sistema operativo ajustado el grado mínimo de un solo elemento es un mecanismo de alimentación

Se pueden crear varios subprocesos en un proceso. Estos subprocesos tienen sus propios contadores, pilas y variables locales, y pueden acceder a las variables de memoria compartida. El procesador activa estos subprocesos a alta velocidad, lo que hace que parezca que estos subprocesos se ejecutan al mismo tiempo.

Tarea prioritaria

Básicamente, el sistema operativo programa la ejecución de subprocesos en forma de división de tiempo. El sistema operativo asignará intervalos de tiempo uno por uno, y los subprocesos se asignarán varios intervalos de tiempo. Cuando se agoten los intervalos de tiempo del subproceso, se producirá la programación de subprocesos y esperará la siguiente asignación. El intervalo de tiempo asignado por el subproceso determina la cantidad de recursos del procesador que utiliza el subproceso, y la prioridad del subproceso es el atributo del subproceso que determina cuánto o menos necesita el subproceso para asignar algunos recursos del procesador.

En los subprocesos de Java, la prioridad varía de 1 a 10, y la prioridad predeterminada es 5. A los subprocesos con alta prioridad se les asignan más intervalos de tiempo que a los subprocesos con baja prioridad.

Estado del hilo

public class ThreadState {


    private static Lock lock = new ReentrantLock();


public static void main(String[] args) {

//线程被构建,处于NEW状态

Thread thread=new Thread(new TimeWaiting(), "TimeWaitingThread");

//线程开始,即将进入RUNNABLE状态

        thread.start();

        new Thread(new Waiting(), "WaitingThread").start();

        // 使用两个Blocked线程,一个获取锁成功,另一个被阻塞

        new Thread(new Blocked(), "BlockedThread-1").start();

        new Thread(new Blocked(), "BlockedThread-2").start();

        new Thread(new Sync(), "SyncThread-1").start();

        new Thread(new Sync(), "SyncThread-2").start();

    }


    /**

     * 该线程不断的进行睡眠

     */

    static class TimeWaiting implements Runnable {

        @Override

        public void run() {

            while (true) {

                SleepUtils.second(100);

            }

        }

    }


    /**

     * 该线程在Waiting.class实例上等待

     */

    static class Waiting implements Runnable {

        @Override

        public void run() {

            while (true) {

                synchronized (Waiting.class) {

                    try {

                        Waiting.class.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }


    /**

     * 该线程在Blocked.class实例上加锁后,不会释放该锁

     */

    static class Blocked implements Runnable {

        public void run() {

            synchronized (Blocked.class) {

                while (true) {

                    SleepUtils.second(100);

                }

            }

        }

    }


    static class Sync implements Runnable {


        @Override

        public void run() {

            lock.lock();

            try {

                SleepUtils.second(100);

            } finally {

                lock.unlock();

            }


        }


    }

}

Analice el estado de ejecución del hilo a través de jstack pid:

 

Transición del estado del hilo de Java

Nota: Java combina los estados en ejecución y listo en el sistema operativo como el estado en ejecución. El estado de bloqueo es el estado en el que el subproceso se bloquea al ingresar al método o bloque de código modificado por la palabra clave sincronizada (adquiriendo el bloqueo), pero el estado del subproceso bloqueado en la interfaz Lock en el paquete java.concurrent es un estado de espera, porque la interfaz Lock en el paquete java.concurrent Para la implementación del bloqueo, se utilizan los métodos relevantes en la clase LockSupport.

 

El hilo de Daemon es un tipo de hilo de soporte, porque se utiliza principalmente para la programación en segundo plano y el trabajo de soporte en el programa. Cuando no hay subprocesos que no sean Daemon en una máquina virtual Java, la máquina virtual Java se cerrará.

 

Nota: El atributo Daemon debe establecerse antes de iniciar el hilo y no puede establecerse después de iniciar el hilo.

El subproceso Daemon se utiliza para completar el trabajo de apoyo, pero el bloque finalmente en el subproceso Daemon no se ejecuta necesariamente cuando la máquina virtual Java sale

Interrupción del hilo

La interrupción puede entenderse como un atributo de bandera de un hilo, que indica si un hilo en ejecución ha sido interrumpido por otros hilos. La interrupción es como si otro hilo saludara al hilo, y otros hilos interrumpen el hilo llamando al método interrupt () del hilo.

El hilo responde verificando si está interrumpido. El hilo usa el método isInterrupted () para determinar si está interrumpido. También puedes llamar al método estático Thread.interrupted () para restablecer la bandera de interrupción del hilo actual. Si el hilo ya está en el estado terminal, incluso si el hilo se interrumpe, seguirá devolviendo falso al llamar a isInterrupted () del objeto hilo.

 

Nota: Los métodos suspender (), reanudar () y detener () completan la suspensión, reanudación y terminación de los hilos, y son muy "humanos". Pero estas API están desactualizadas, lo que no se recomienda.

 

La palabra clave volatile se puede usar para modificar el campo (variable miembro), que es para informar al programa que cualquier acceso a la variable debe obtenerse de la memoria compartida, y los cambios a ella deben ser devueltos a la memoria compartida sincrónicamente. Puede garantizar que todos los subprocesos accedan a la variable Visibilidad.

La palabra clave sincronizada se puede utilizar para modificar el método o en forma de bloque sincronizado. Principalmente asegura que varios subprocesos solo pueden estar en el método o bloque sincronizado al mismo tiempo. Garantiza la visibilidad y visibilidad del acceso del subproceso a las variables. Exclusividad.

public class Synchronized {

    public static void main(String[] args) {

        // 对Synchronized Class对象进行加锁

        synchronized (Synchronized.class) {


        }

        // 静态同步方法,对Synchronized Class对象进行加锁

        m();

    }


    public static synchronized void m() {

    }

}

通过javap -v Synchronized .class

 El descomponedor de archivos de clase Java puede descompilar (es decir, descompilar los archivos compilados por javac) o ver el código de bytes generado por el compilador de Java. Se utiliza para descomponer archivos de clases.

Para la realización del bloque de sincronización se utilizan las instrucciones monitorenter y monitorexit, y el método de sincronización se completa con el ACC_SYNCHRONIZED en el modificador de método.

Mecanismo de espera / notificación

1) Al usar wait (), notificar () y notificar a todos (), primero debe bloquear el objeto que realiza la llamada.

2) Después de llamar al método wait (), el estado del hilo cambia de RUNNING a WAITING, y el hilo actual se coloca en la cola de espera del objeto.

3) Después de que se llama al método notificar () o notificarAll (), el hilo en espera todavía no regresará de wait (). Después de que el hilo que llama a notificar () o notifAll () libera el bloqueo, el hilo en espera tiene la oportunidad de regresar de esperar ().

4) El método notify () mueve un subproceso en espera en la cola de espera desde la cola de espera a la cola de sincronización, mientras que el método notifyAll () mueve todos los subprocesos en la cola de espera a la cola de sincronización. El estado del subproceso movido está determinado por La ESPERA se bloquea.

5) La premisa de regresar del método wait () es obtener el bloqueo del objeto que llama.

public class WaitNotify {

    static boolean flag = true;

    static Object  lock = new Object();


    public static void main(String[] args) throws Exception {

        Thread waitThread = new Thread(new Wait(), "WaitThread");

        waitThread.start();

        TimeUnit.SECONDS.sleep(1);


        Thread notifyThread = new Thread(new Notify(), "NotifyThread");

        notifyThread.start();

    }


    static class Wait implements Runnable {

        public void run() {

            // 加锁,拥有lock的Monitor

            synchronized (lock) {

                // 当条件不满足时,继续wait,同时释放了lock的锁

                while (flag) {

                    try {

                        System.out.println(Thread.currentThread() + " flag is true. wait @ "

                                           + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                        lock.wait();

                    } catch (InterruptedException e) {

                    }

                }

                // 条件满足时,完成工作

                System.out.println(Thread.currentThread() + " flag is false. running @ "

                                   + new SimpleDateFormat("HH:mm:ss").format(new Date()));

            }

        }

    }


    static class Notify implements Runnable {

        public void run() {

            // 加锁,拥有lock的Monitor

            synchronized (lock) {

                // 获取lock的锁,然后进行通知,通知时不会释放lock的锁,

                // 直到当前线程释放了lock后,WaitThread才能从wait方法中返回

                System.out.println(Thread.currentThread() + " hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                lock.notifyAll();

                flag = false;

                SleepUtils.second(5);

            }

            // 再次加锁

            synchronized (lock) {

                System.out.println(Thread.currentThread() + " hold lock again. sleep @ "

                                   + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                SleepUtils.second(5);

            }

        }

}

WaitThread primero adquiere el bloqueo del objeto y luego llama al método wait () del objeto, abandonando así el bloqueo y entrando en la cola de espera del objeto WaitQueue, entrando en el estado de espera. Debido a que WaitThread libera el bloqueo del objeto, NotifyThread posteriormente adquiere el bloqueo del objeto y llama al método notificar () del objeto para mover WaitThread de WaitQueue a

En SynchronizedQueue, el estado de WaitThread se bloquea en este momento. Después de que NotifyThread libera el bloqueo, WaitThread vuelve a adquirir el bloqueo y regresa del método wait () para continuar con la ejecución.

Thread.join ()

El hilo actual A espera que termine el hilo antes de regresar de thread.join ()

ThreadLocal

Es una estructura de almacenamiento con objetos ThreadLocal como claves y objetos arbitrarios como valores. Esta estructura se adjunta al hilo, lo que significa que un hilo puede consultar un valor vinculado a este hilo basado en un objeto ThreadLocal.

Supongo que te gusta

Origin blog.csdn.net/weixin_44416039/article/details/86160970
Recomendado
Clasificación