Sincronización de subprocesos múltiples (5)

Sincronización de subprocesos múltiples (5)

  1. Condiciones para la formación de subprocesos múltiples: cola + bloqueo (por seguridad)

  2. La sincronización de subprocesos es segura, primero veamos la inseguridad de los subprocesos

    • Un ejemplo de inseguridad en los hilos:

      //不安全的买票
      //线程不安全,有负数
      public class UnsafeBuyTicket {
              
              
          public static void main(String[] args) {
              
              
              BuyTicket station=new BuyTicket();
      
              new Thread(station,"苦逼的我").start();
              new Thread(station,"牛逼的你们").start();
              new Thread(station,"可恶的黄牛党").start();
          }
      
      
      }
      
      class BuyTicket implements Runnable{
              
              
      
          //票
          private int ticketNums=10;
          boolean flag=true;//外部停止方式
          @Override
          public void run() {
              
              
              //买票
              while (flag){
              
              
                  try {
              
              
                      buy();
                  } catch (InterruptedException e) {
              
              
                      e.printStackTrace();
                  }
              }
      
          }
      
          private void buy() throws InterruptedException {
              
              
              //判断是否有票
              if (ticketNums<=0){
              
              
                  flag =false;
                  return;
              }
              //模拟延时
              Thread.sleep(100);
              //买票
              System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
          }
      }
      
    • El primer ejemplo de inseguridad de subprocesos, el diagrama esquemático de la situación donde aparece -1:

Inserte la descripción de la imagen aquí

  • El segundo ejemplo de inseguridad en los hilos:

    //不安全的取钱
    //两个人去银行取钱,账户
    public class UnsafeBank {
          
          
        public static void main(String[] args) {
          
          
            //账户
            Account account=new Account(100,"结婚基金");
    
            Drawing you=new Drawing(account,50,"你");
            Drawing girlFriend=new Drawing(account,100,"girlFriend");
    
            you.start();
            girlFriend.start();
    
        }
    }
    
    //账户
    class Account{
          
          
        int money;//余额
        String name;//卡名
    
        public Account(int money,String name){
          
          
            this.money=money;
            this.name=name;
        }
    }
    
    //银行:模拟取款
    class Drawing extends Thread{
          
          
    
        Account account;//账户
        //取了多少钱
        int drawingMoney;
        //现在手里有多少钱
        int nowMoney;
    
        public Drawing(Account account, int drawingMoney,String name){
          
          
            super(name);//调用父类的有参构造
            this.account=account;
            this.drawingMoney=drawingMoney;
        }
    
        //取钱
        @Override
        public void run() {
          
          
            //判断有没有钱
            if (account.money-drawingMoney<0){
          
          
                System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                return;
            }
    
            //sleep可以放大问题的发生性
            try {
          
          
                Thread.sleep(1000);
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
    
            //卡内余额= 余额-你取的钱
            account.money = account.money-drawingMoney;
            //你手里的钱
            nowMoney = nowMoney+drawingMoney;
    
            System.out.println(account.name+"余额为:"+account.money);
            //Thread.currentThread().getName()=this.getName() //获取线程名字
            System.out.println(this.getName()+"手里的钱:"+nowMoney);
        }
    }
    
  • El segundo ejemplo de inseguridad de subprocesos, el diagrama esquemático de la situación donde hay un saldo de -50:

Inserte la descripción de la imagen aquí

  • Tres ejemplos de inseguridad en los hilos:

    import java.util.ArrayList;
    import java.util.List;
    
    //线程不安全的集合
    public class UnsafeList {
          
          
        public static void main(String[] args) {
          
          
            List<String> list=new ArrayList<>();
            for (int i = 0; i < 10000; i++) {
          
          
                new Thread(()->{
          
          //不安全的原因:因为2个线程同一个瞬间操作了同一个位置,把两个数组添加了同一个位置就把它覆盖掉了,覆盖掉了,元素就会少,少的元素就是这么来的
                    list.add(Thread.currentThread().getName());
                }).start();
            }
            try {
          
          
                Thread.sleep(3000);//让他睡3秒,放大问题的发生性,还是打印不到1w个线程
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
            System.out.println(list.size());//线程的大小没能够按照理论的打印1w个线程
        }
    }
    
    
  1. Razones de la inseguridad del hilo :

    Cada subproceso interactúa en su propia memoria de trabajo. Un control inadecuado de la memoria causará inconsistencia en los datos. Para decirlo sin rodeos, la memoria del hilo es propia, de hecho, cada hilo tendrá la memoria del sistema y la memoria será negativa, lo que también conduce a la inseguridad del hilo.

  2. Para resolver el problema de la inseguridad del hilo es: utilizar el método de sincronización

    • Proponemos un conjunto de mecanismos para este método, este conjunto de mecanismos es la palabra clave sincronizada, incluye dos métodos: método sincronizado y bloque sincronizado

      El método de sincronización: método void sincronizado público (int args ) {}

    • El método sincronizado controla el acceso al " objeto ". Cada objeto corresponde a un bloqueo. Cada método sincronizado debe llamar al bloqueo del objeto del método a ejecutar, de lo contrario el hilo se bloqueará. Una vez que se ejecuta el método, el bloqueo se se utilizará exclusivamente hasta que el método vuelva a liberar el bloqueo, y el hilo bloqueado pueda adquirir el bloqueo y continuar la ejecución

      Defectos: si un método grande se declara como sincronizado, afectará la eficiencia

Inserte la descripción de la imagen aquí

  • Bloque sincronizado: sincronizado ( Obj ) {}
  • Obj lo llama monitor de sincronización
    • Obj puede ser cualquier objeto, pero se recomienda utilizar recursos compartidos como monitor de sincronización.
    • No es necesario especificar un monitor de sincronización en el método de sincronización, porque el monitor de sincronización del método de sincronización es este, que es el objeto en sí, o la clase [explicado en la reflexión]
  • El proceso de ejecución del monitor de sincronización: el principio del método sincronizado es el mismo
  1. El primer ejemplo de solución de la inseguridad de subprocesos es agregar la palabra clave sincronizada al método buy () para convertirlo en un método de sincronización sincronizado .

    //不安全的买票
    //线程不安全,有负数
    public class UnsafeBuyTicket {
          
          
        public static void main(String[] args) {
          
          
            BuyTicket station=new BuyTicket();
    
            new Thread(station,"苦逼的我").start();
            new Thread(station,"牛逼的你们").start();
            new Thread(station,"可恶的黄牛党").start();
        }
    
    
    }
    
    class BuyTicket implements Runnable{
          
          
    
        //票
        private int ticketNums=10;
        boolean flag=true;//外部停止方式
        @Override
        public void run() {
          
          
            //买票
            while (flag){
          
          
                try {
          
          
                    buy();
                } catch (InterruptedException e) {
          
          
                    e.printStackTrace();
                }
            }
    
        }
    
        //synchronized 同步方法,锁的是this
        private synchronized void buy() throws InterruptedException {
          
          
            //判断是否有票
            if (ticketNums<=0){
          
          
                flag =false;
                return;
            }
            //模拟延时
            Thread.sleep(100);
            //买票
            System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
        }
    }
    
  2. El segundo ejemplo de solución de la inseguridad de subprocesos solo se puede resolver bloqueando un bloque de cuenta sincronizado.

    //不安全的取钱
    //两个人去银行取钱,账户
    public class UnsafeBank {
          
          
        public static void main(String[] args) {
          
          
            //账户
            Account account=new Account(100,"结婚基金");
    
            Drawing you=new Drawing(account,50,"你");
            Drawing girlFriend=new Drawing(account,100,"girlFriend");
    
            you.start();
            girlFriend.start();
    
        }
    }
    
    //账户
    class Account{
          
          
        int money;//余额
        String name;//卡名
    
        public Account(int money,String name){
          
          
            this.money=money;
            this.name=name;
        }
    }
    
    //银行:模拟取款
    class Drawing extends Thread{
          
          
    
        Account account;//账户
        //取了多少钱
        int drawingMoney;
        //现在手里有多少钱
        int nowMoney;
    
        public Drawing(Account account, int drawingMoney,String name){
          
          
            super(name);//调用父类的有参构造
            this.account=account;
            this.drawingMoney=drawingMoney;
        }
    
        //取钱
        //synchronized 默认锁的是this
        @Override
        public  void run() {
          
          
            synchronized (account){
          
          //这里只有锁的是account的同步块才有用,锁run()方法是没用的
                //判断有没有钱
                if (account.money-drawingMoney<0){
          
          
                    System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                    return;
                }
    
                //sleep可以放大问题的发生性
                try {
          
          
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
          
          
                    e.printStackTrace();
                }
    
                //卡内余额= 余额-你取的钱
                account.money = account.money-drawingMoney;
                //你手里的钱
                nowMoney = nowMoney+drawingMoney;
    
                System.out.println(account.name+"余额为:"+account.money);
                //Thread.currentThread().getName()=this.getName() //获取线程名字
                System.out.println(this.getName()+"手里的钱:"+nowMoney);
            }
            }
    
    }
    
  3. El tercer ejemplo de solución de la inseguridad de subprocesos es utilizar una lista de bloqueo de bloque sincronizada.

    import java.util.ArrayList;
    import java.util.List;
    
    //线程不安全的集合
    public class UnsafeList {
          
          
        public static void main(String[] args) {
          
          
            List<String> list=new ArrayList<>();
            for (int i = 0; i < 10000; i++) {
          
          
                new Thread(()->{
          
          //不安全的原因:因为2个线程同一个瞬间操作了同一个位置,把两个数组添加了同一个位置就把它覆盖掉了,覆盖掉了,元素就会少,少的元素就是这么来的
                   synchronized (list){
          
          
                       list.add(Thread.currentThread().getName());
                   }
                }).start();
            }
            try {
          
          
                Thread.sleep(3000);//让他睡3秒,放大问题的发生性,还是打印不到1w个线程
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
            System.out.println(list.size());//线程的大小没能够按照理论的打印1w个线程
        }
    }
    
    
  4. Suplemento: La colección de tipos de seguridad de JUC también puede resolver algunos problemas de seguridad de subprocesos.

import java.util.concurrent.CopyOnWriteArrayList;

//测试JUC安全类型的集合
public class TestJUC {
    
    
    public static void main(String[] args) {
    
    
        //concurrent并发包下写好的,安全的ArrayList
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
    
    
            new Thread(()->{
    
    
                list.add(Thread.currentThread().getName());
            }).start();
        }

        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(list.size());

    }
}

Supongo que te gusta

Origin blog.csdn.net/Xun_independent/article/details/114992908
Recomendado
Clasificación