【狂神说Java】线程同步方法&同步块

同步方法

  • 对方法加上synchronized关键字
  • synchronized的方法调用时都需要得到该方法的锁,否则无法执行。线程执行完毕释放锁后,其他线程才能获得这个锁。
  • 若将一个大的方法申明为synchronized会影响效率。
    • 方法里面需要修改内容菜需要锁,锁太多,浪费资源。

安全买票

public class SafeBuyTicket  {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        // new三个线程同时操作一个对象
        new Thread(buyTicket,"a").start();
        new Thread(buyTicket,"b").start();
        new Thread(buyTicket,"c").start();

    }
}

class BuyTicket implements Runnable{
    private int ticketNums = 10;//总共10张票
    private boolean flag = true;

    private synchronized void buy() {
        // 买票
        if (ticketNums <= 0) {
            flag = false;
            return;
        }try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "抢到了第" + (ticketNums--) + "张票");

    }

    @Override
    public void run() {
        while (flag) {
            buy();
        }
    }
}

同步块

  • 同步块:synchronized(Obj){代码}
  • Obj称之为同步监视器,需要锁的对象是增删改查的对象
    • Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
    • 同步方法中无需指定同步监视器,因为同步方法的监视器就是this就是它本身,或者是class
  • 同步监视器执行过程
    1. 第一个线程访问,锁定同步监视器,执行其中代码
    2. 第二个线程访问,发现同步监视器被锁定,无法访问
    3. 第一个线程访问完毕,解锁同步监视器
    4. 第二个线程访问,发现同步监视器没有锁,然后锁定访问
public class SafeDrawing {
   public static void main(String[] args) {
       Account account = new Account(200,"1123");
       Drawing a = new Drawing(account,100,0,"aaa");
       Drawing b = new Drawing(account,200,0,"bbb");

       a.start();
       b.start();
   }
}

class Account{

   public Account(int money, String id) {
       this.money = money;
       this.id = id;
   }

   // 银行账户
   int money;// 余额
   String id;// 账号

}

class Drawing extends Thread{
   Account account; // 账户
   int drawingMoney; //取钱
   int nowMoney; // 手上的钱

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

   @Override
   public void run() {
       // 同步代码块
       synchronized (account){
           // 判断有没有钱
           if (account.money < drawingMoney){
               System.out.println("钱不够");
               return;
           }

           try {
               Thread.sleep(100);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           // 账户上的钱
           account.money -= drawingMoney;
           // 你手里的钱
           nowMoney += drawingMoney;

           System.out.println(account.id+ "账户余额为:"+ account.money);
           System.out.println(this.getName() + "手里的钱为:"+ nowMoney);
       }
   }
}
posted @ 2021-09-18 17:38  Jie7  阅读(57)  评论(0)    收藏  举报