同步方法

同步方法

  • 由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要对这个方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:
    • synchronized 方法 和 synchronized

    • 同步方法: public  synchronized void method(int args){}
      
    • synchronized 方法控制“对象”的访问,每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁才能够执行,否则线程会阻塞,方法一旦执行,就独占该锁,知道方法返回才能释放锁,后面被阻塞的线程才能获得这个锁,继续执行

    • 缺陷: 若将一个大的方法申明为  synchronized 将会影响效率
      
  • //买票 (线程出现负数)
    public class Demo01 {
        public static void main(String[] args) {
            BuyTickets buyTickets = new BuyTickets();
            new Thread(buyTickets,"person1").start();
            new Thread(buyTickets,"person2").start();
            new Thread(buyTickets,"person3").start();
        }
    }
    class BuyTickets implements Runnable{
        private int ticketNum = 10;
        boolean flag = true;
        @Override
        public void run() {
            while (flag){
                try {
                    buy();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        // synchronized 同步方法,锁的是this(也就是锁的是当前类)
        private synchronized void buy() throws Exception {
            //判断是否有票
            if (ticketNum < 1){
                flag = false;
                return;
            }
            //模拟延时
            Thread.sleep(100);
            //买票
            System.out.println(Thread.currentThread().getName()+"第"+ticketNum--+"张票");
        }
    }
    
  • 同步块

    • 同步块: synchronized( Obj ){ }
    • Obj 称之为同步监视器
      • Obj 可以是任何对象,但是推荐使用共享资源作为同步监视器
      • 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this
    • 同步监视器的执行过程
      • 第一个线程访问,锁定同步监视器,执行其中代码
      • 第二个线程访问,发现同步监视器被锁定,无法访问
      • 第一个线程访问完毕,解锁同步监视器
      • 第二个线程访问,发现同步监视器没有锁,然后锁定并访问
    //不安全取款   用synchronized(Obj){}
    public class Demo02 {
        public static void main(String[] args) {
            //账户
            Account account = new Account(100,"A");
            Bank person1 = new Bank(account, 20, "Person1");
            Bank person2 = new Bank(account, 90, "person2");
            person1.start();
            person2.start();
        }
    }
    //账户
    class Account{
        int money;
        String name;
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }
    //银行(synchronized 方法也就是锁的是当前类,这里锁银行并无用)
    class Bank extends Thread{
        Account account;
        int outMoney;
        int nowMoney;
        public Bank(Account account,int outMoney,String name){
            super(name);
            this.outMoney = outMoney;
            this.account = account;
        }
    
        @Override
        public void run() {
            //锁的对象是变化的量,增删改
            synchronized (account){ //锁定账户
                //判断是否还有钱
                if(account.money-outMoney<0){
                    System.out.println(Thread.currentThread().getName()+"钱不够了");
                    return;
                }
                //sleep可以放大问题的发生性
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                //卡内余额
                account.money = account.money - outMoney;
                //手里的钱
                nowMoney = nowMoney +outMoney;
                System.out.println(account.name+"余额为:"+account.money);
                //Thread.currentThread().getName() =  this.getName()
                System.out.println(this.getName()+"手里的钱"+nowMoney);
            }
        }
    }
    

posted @ 2021-04-25 14:50  saxon宋  阅读(269)  评论(0)    收藏  举报