同步方法
同步方法
-
由于我们可以通过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); } } }

浙公网安备 33010602011771号