线程同步synchronized锁(同步方法)

线程同步

1.并发

并发∶同一个对象被多个线程同时操作

2.线程同步

处理多线程问题时,多个线程访问同一个对象﹐并且某些线程还想修改这个对象.这时候我们就需要线程同步﹒线程同步其实就是一种等待机制﹐多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。

3.队列和锁

为了解决安全性 锁机制 (synchronized)

4.线程安全
  1. 线程不安全三个例子

    / 不安全取钱
    // 两个人去取钱
    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");

           new Thread(you).start();
           new Thread(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 noMoney;

       public Drawing(Account account,int drawingMoney,String name){
           super(name);
           this.account =account;
           this.drawingMoney =drawingMoney;
      }

       // 取钱
       public void run(){
           //判断有没有钱
           if(account.money-drawingMoney<0){
               System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
               return;
          }
           // Thread.sleep(100);造成线程不安全
           try {
               Thread.sleep(100);
          } catch (InterruptedException e) {
               throw new RuntimeException(e);
          }
           // 卡内余额 = 余额 - 取出的钱
           account.money = account.money -drawingMoney;
           // 手里的钱
           noMoney = noMoney + drawingMoney;

           System.out.println(account.name+"余额位:"+account.money);
           // Thread.currentThread().getName() = this.getName();
           System.out.println(this.getName()+"手里的钱:"+noMoney);
      }
    }
    // 不安全买票
    // 线程不安全
    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) {
                   throw new RuntimeException(e);
              }
          }

      }

       private void buy() throws InterruptedException {
           // 判断是否有票
           if(ticketNums<=0){
               return;
          }
           // 模拟延时
           try {
               Thread.sleep(100);
          } catch (InterruptedException e) {
               throw new RuntimeException(e);
          }
           // 买票
           System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
      }
    }

     

// 不安全集合
public class UnSafeList {
   public static void main(String[] args) throws InterruptedException {
       List<String> list = new ArrayList<String>();
       for (int i = 0; i < 10000; i++) {
           new Thread(()->{
               list.add(Thread.currentThread().getName());
          }).start();
      }
       try {
           Thread.sleep(300);
      } catch (InterruptedException e) {
           throw new RuntimeException(e);
      }
       System.out.println(list.size());
  }
}
5.同步方法
  1. 由于我们可以通过private关键字来保证数据对象只能被方法访问﹐所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法︰synchronized方法和synchronized 块。

  2. 同步方法:public synchronized void method(int args){ }

  3. synchronized方法控制对“对象”的访问﹐每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行﹐否则线程会阻塞,方法一旦执行﹐就独占该锁,直到该方法返回才释放锁﹐后面被阻塞的线程才能获得这个锁,继续执行。

  4. 缺陷:若将一个大的方法申明为synchronized将会影响效率。

  5. synchronized默认锁这个对象

  6. 同步块:synchronized(obj){ }

  7. Obj称之为同步监视器,Obj可以是任何对象﹐但是推荐使用共享资源作为同步监视器,同步方法中无需指定同步监视器﹐因为同步方法的同步监视器就是this ,就是这个对象本身,或者是 class [反射中讲解]。

  8. 同步监视器的执行过程:

    1. 第一个线程访问,锁定同步监视器﹐执行其中代码.

    2. 第二个线程访问﹐发现同步监视器被锁定﹐无法访问.

    3. 第一个线程访问完毕﹐解锁同步监视器﹒

    4. 第二个线程访问,发现同步监视器没有锁﹐然后锁定并访问

    锁的对象是变化的量

    1. 锁对象为this

      / 不安全买票
      // 线程不安全
      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 = 100;
         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. 锁对象为任意对象

      package com.yuan.syn;

      // 不安全取钱
      // 两个人去取钱
      public class UnSafeBank {
         public static void main(String[] args) {
             // 账户
             Account account =  new Account(10000,"结婚存款");

             Drawing you = new Drawing(account,50,"你");
             Drawing girlFriend = new Drawing(account,100,"girlFriend");

             new Thread(you).start();
             new Thread(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 noMoney;

         public Drawing(Account account,int drawingMoney,String name){
             super(name);
             this.account =account;
             this.drawingMoney =drawingMoney;
        }

         // 取钱
         public void run(){
             synchronized (account){
                 //判断有没有钱
                 if(account.money-drawingMoney<0){
                     System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                     return;
                }
                 // Thread.sleep(100);造成线程不安全
                 try {
                     Thread.sleep(100);
                } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                }
                 // 卡内余额 = 余额 - 取出的钱
                 account.money = account.money -drawingMoney;
                 // 手里的钱
                 noMoney = noMoney + drawingMoney;

                 System.out.println(account.name+"余额位:"+account.money);
                 // Thread.currentThread().getName() = this.getName();
                 System.out.println(this.getName()+"手里的钱:"+noMoney);
            }

        }
      }

      切记:锁的对象是变化的量

    3.  
posted @   Y~~~  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示