Multithreading-thread synchronization (5)

Multithreading-thread synchronization (5)

  1. Conditions for the formation of multithreading: queue + lock (for safety)

  2. Thread synchronization is safe, let's first look at the insecurity of threads

    • One example of thread insecurity:

      //不安全的买票
      //线程不安全,有负数
      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--);
          }
      }
      
    • The first example of thread insecurity, the schematic diagram of the situation where -1 appears:

Insert picture description here

  • The second example of thread insecurity:

    //不安全的取钱
    //两个人去银行取钱,账户
    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);
        }
    }
    
  • The second example of thread insecurity, the schematic diagram of the situation where there is a balance of -50:

Insert picture description here

  • Three examples of thread insecurity:

    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. Reasons for thread insecurity :

    Each thread interacts in its own working memory. Improper memory control will cause data inconsistency. To put it bluntly, the memory of the thread is its own. In fact, each thread will have the memory of the system, and the memory will be negative, which also leads to the insecurity of the thread.

  2. To solve the problem of thread insecurity is: use the synchronization method

    • We propose a set of mechanisms for this method, this set of mechanisms is the synchronized keyword, he includes two methods: synchronized method and synchronized block

      The synchronization method: public synchronized void method (int args ) {}

    • The synchronized method controls the access to the " object ". Each object corresponds to a lock. Each synchronized method must call the lock of the object of the method to execute, otherwise the thread will block. Once the method is executed, the lock will be exclusively used until the The method returns to release the lock, and the blocked thread can acquire the lock and continue execution

      ​ Defects: If a large method is declared as synchronized, it will affect efficiency

Insert picture description here

  • Synchronized block : synchronized( Obj ){}
  • Obj calls it a sync monitor
    • Obj can be any object, but it is recommended to use shared resources as a synchronization monitor
    • There is no need to specify a synchronization monitor in the synchronization method, because the synchronization monitor of the synchronization method is this, which is the object itself, or class [explained in reflection]
  • The execution process of the synchronization monitor: the principle of the synchronized method is the same
  1. The first example of solving thread insecurity is to add the synchronized keyword to the buy() method to turn it into a synchronized synchronization method .

    //不安全的买票
    //线程不安全,有负数
    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. The second example of solving thread insecurity can be solved only by locking a synchronized block of account.

    //不安全的取钱
    //两个人去银行取钱,账户
    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. The third example of solving thread insecurity is to use a synchronized block lock list.

    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. Supplement: The collection of JUC safety types can also solve some thread safety issues.

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());

    }
}

Guess you like

Origin blog.csdn.net/Xun_independent/article/details/114992908