Programación concurrente y de subprocesos múltiples [subproceso Daemon, sincronización de subprocesos] (3) - explicación detallada completa (resumen de aprendizaje --- desde la entrada hasta la profundización)

 

 

Tabla de contenido

hilo de demonio

 ¿Qué es un hilo demonio?

 El uso de subprocesos daemon

sincronización de subprocesos

Implementar la sincronización de subprocesos

El uso de la sincronización de subprocesos


hilo de demonio

 ¿Qué es un hilo demonio?

  Hay dos tipos de hilos en Java:

        User Thread (hilo de usuario): Es un hilo personalizado en la aplicación.

        Subproceso de daemon: por ejemplo, el subproceso de recolección de basura es el subproceso de daemon más típico.

 El hilo daemon (es decir, Daemon Thread) es un hilo de servicio, para ser precisos, es para servir a otros hilos, ese es su rol, y solo hay otro hilo, es decir, el hilo de usuario.

 Características del subproceso Daemon :

      Los subprocesos de daemon mueren a medida que mueren los subprocesos de usuario.

La diferencia entre subprocesos de daemon y subprocesos de usuario :

Los subprocesos de usuario no mueren con la muerte del subproceso principal. Solo hay dos situaciones en las que los subprocesos de usuario morirán, una es una terminación anormal en ejecución. 2 La ejecución se ejecuta normalmente y el subproceso muere.

El subproceso daemon muere con la muerte del subproceso de usuario, y el subproceso daemon también morirá cuando el subproceso de usuario muere.

 El uso de subprocesos daemon

/**
* 守护线程类
*/
class Daemon implements  Runnable{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
              System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(2000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
class UsersThread implements Runnable{
    @Override
    public void run() {
        Thread t = new Thread(new Daemon(),"Daemon");
        //将该线程设置为守护线程
        t.setDaemon(true);
        t.start();
        for(int i=0;i<5;i++){
          System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(500);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
public class DaemonThread {
    public static void main(String[] args)throws Exception {
        Thread t = new Thread(new UsersThread(),"UsersThread");
        t.start();
        Thread.sleep(1000);
        System.out.println("主线程结束");
   }
}

sincronización de subprocesos

¿Qué es la sincronización de subprocesos?

conflicto de hilos

 Pregunta de sincronización planteada

En la vida real, nos encontraremos con el problema de "varias personas quieren usar el mismo recurso". Por ejemplo: solo hay una computadora en el salón de clases y varias personas quieren usarla. La solución natural es alinearse al lado de la computadora. Después de que la persona anterior termine de usarlo, la última persona lo usará nuevamente.

 El concepto de sincronización de subprocesos

Cuando se trata de problemas de subprocesos múltiples, varios subprocesos acceden al mismo objeto y algunos subprocesos también desean modificar este objeto. En este momento, necesitamos usar "sincronización de subprocesos". La sincronización de subprocesos es en realidad un mecanismo de espera. Múltiples subprocesos que necesitan acceder a este objeto al mismo tiempo ingresan al grupo de espera de este objeto para formar una cola y esperan a que se use el subproceso anterior antes de que el siguiente subproceso pueda usarlo.

Demostración de caso de conflicto de subprocesos 

Usamos el caso clásico de retiro bancario para demostrar el fenómeno del conflicto de hilos. El proceso básico de retiros bancarios básicamente se puede dividir en los siguientes pasos.

(1) El usuario ingresa la cuenta y la contraseña, y el sistema juzga si la cuenta y la contraseña del usuario coinciden.

(2) El usuario ingresa el monto del retiro

(3) El sistema juzga si el saldo de la cuenta es mayor o igual al monto del retiro

(4) Si el saldo es mayor o igual al monto del retiro, el retiro es exitoso; si el saldo es menor que el monto del retiro, el retiro falla.

/**
* 账户类
*/
class Account{
    //账号
    private String accountNo;
    //账户的余额
    private double balance;
    public Account() {
   }
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
   }
    public String getAccountNo() { return accountNo;
   }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
   }
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程
 */
    @Override
    public void run() {
        //判断当前账户余额是否大于或等于取款金额
        if(this.account.getBalance() >= this.drawMoney){
          System.out.println(Thread.currentThread().getName()+" 取钱成功!吐出钞
票:"+this.drawMoney);
            try {
                Thread.sleep(1000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
            //更新账户余额
          this.account.setBalance(this.account.getBalance()- this.drawMoney);
            System.out.println("\t 余额为:"+this.account.getBalance());
       }else{
          System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

Implementar la sincronización de subprocesos

Dado que varios subprocesos del mismo proceso comparten el mismo espacio de almacenamiento, además de brindar comodidad, también genera el problema de los conflictos de acceso. El lenguaje Java proporciona un mecanismo especial para resolver este conflicto, evitando efectivamente el problema causado por el acceso al mismo objeto de datos por parte de múltiples subprocesos al mismo tiempo. Este mecanismo es la palabra clave sincronizada.

 Estructura de sintaxis sincronizada:

synchronized(锁对象){ 
   同步代码
 }

Cuestiones a tener en cuenta al usar la palabra clave sincronizada:

    Es necesario tener la capacidad de exclusión mutua de subprocesos (subproceso de exclusión mutua: paralelo a serie) para esa parte del código durante la ejecución.

   Códigos en los que los subprocesos deben tener capacidades de exclusión mutua (determinadas por objetos de bloqueo sincronizados).

Incluye dos usos:

métodos sincronizados y bloques sincronizados.

 1 método sincronizado 

    Declare agregando la palabra clave sincronizada en la declaración del método, la sintaxis es la siguiente:

    

public  synchronized  void accessVal(int newVal);

Synchronized se usa en declaraciones de métodos: antes o después del carácter de control de acceso (público). En este momento, cuando el método sincronizado bajo el mismo objeto se ejecuta en varios subprocesos, el método se sincroniza, es decir, solo un subproceso puede ingresar al método a la vez. Si otros subprocesos desean llamar al método en este momento, deben solo puede esperar en línea El subproceso actual (es decir, el subproceso dentro del método sincronizado) Después de ejecutar el método, otros subprocesos pueden ingresar.

2 bloques sincronizados

El defecto del método sincronizado: si un método grande se declara como sincronizado, afectará en gran medida la eficiencia. Java nos proporciona una mejor solución, que es el bloque sincronizado. Los bloques nos permiten controlar con precisión "variables miembro" específicas, reducir el alcance de la sincronización y mejorar la eficiencia.

Modificar demostración de caso de conflicto de subprocesos

/**
* 账户类
*/
class Account{
    //账号
    private String accountNO;
    //账户余额
    private double balance;
    public Account() {
   }
    public Account(String accountNO, double balance) {
        this.accountNO = accountNO;
        this.balance = balance;
   }
    public String getAccountNO() {
        return accountNO;
   }
    public void setAccountNO(String accountNO) {
        this.accountNO = accountNO;
}
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(){
   }
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程体
     */
    @Override
 public void run() {
        synchronized (this.account){
            //判断当前账户余额是否大于或等于取款金额
            if(this.account.getBalance() >= this.drawMoney){
              System.out.println(Thread.currentThread().getName()+" 取钱成功!突出钞票"+this.drawMoney);
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                //更新账户余额
              this.account.setBalance(this.account.getBalance() - this.drawMoney);
                System.out.println("\t 余额为:"+this.account.getBalance());
           }else{
              System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
           }
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

El uso de la sincronización de subprocesos

Use esto como el bloqueo de objeto de hilo

 Estructuras gramaticales:

synchronized(this){
      //同步代码
 }

o

public  synchronized  void accessVal(int newVal){
    //同步代码
}
/**
* 定义程序员类
*/
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
                System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
                System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
                System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
                System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedException e){
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
                System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
                System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
                System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
public class TestSyncThread {
    public static void main(String[] args) {
        Programmer p = new Programmer("张三");
        new Working1(p).start();
        new Working2(p).start();
   }
}

Usar cadena como bloqueo de objeto de hilo

 Estructuras gramaticales:

synchronized(“字符串”){
      //同步代码
 }
/**
* 定义程序员类
*/
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
  */
    synchronized  public  void computer(){
            try {
              System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
              System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
              System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
              System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
              System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
              System.out.println(this.name + " 冲水");
                Thread.sleep(500);
              System.out.println(this.name + " 离开卫生间");
 } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
  this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        Programmer p2 = new Programmer("王五");
        new WC(p).start();
        new WC(p1).start();
        new WC(p2).start();
   }
}

Supongo que te gusta

Origin blog.csdn.net/m0_58719994/article/details/131648281
Recomendado
Clasificación