并发编程 - wait和notifyAll

并发编程之枪械争夺

需求如下图:狙击手们和备弹手们同时争抢一把枪,枪同时只能被一人持有,且备弹容量上限为20。狙击手则使用枪械开枪子弹 -1,备弹手则给枪械上子弹 +1.

问题分析:

    基于面向对象的编程思想,我们首先需要对三者进行抽象,需要创建以下三种类型。

  1. 创建枪械的类,枪械有shot和put方法,有枪械名称和子弹容量等属性。
  2. 创建狙击手类,由于我们是多线程编程,则实现runnable接口,在run方法中使用无限循环调用shot。
  3. 创建备弹手类,实现runnable接口,在run方法中使用无限循环调用put方法。

   在《Effective Java》中,对wait()、notify()、notifyAll()有所描述,作者认为wait()和notifyAll()是组合使用的,结合实际情况来看,确实是这样。如果使用notify()只唤醒一个线程,但是该线程却没有达到获取锁的条件,调用了wait()此时则会发生死锁的情况。

    wait()使用范式:

        while(不满足条件){

              wait();

        }

    notifyAll()使用范式:

       同步代码块,执行结束的最后一行语句,释放锁之前唤醒其他争抢这把锁的线程。

    

    synchronized同步锁使用方式

  1. 同步代码块
  2. 同步方法

    synchronized锁的是什么呢?

    synchronized使用时需要注意以下几点:

  1. synchronized锁要设计好锁的粒度,减少资源的损耗。
  2. synchronized锁声明的方法上,在方法取的方法钱有ANS_SYCHRONIZED标识。
  3. synchronized代码块,则反编译会有monitor enter 和monitor exit方法作为锁开始和结束。jvm实现。
  4. synchronized是可重入锁。
  5. synchronized锁代码区间若抛出异常则释放锁。
  6. synchronized锁静态方法其实锁的是静态方法所属的类对象。
  7. synchronized锁普通方法锁的是这个类当前的实例对象。
  8. 一个类中多个方法、synchronized锁不同的对象,不争夺同一把锁的方法可以并行执行。

代码编写


public class Weapon {


    public static void main(String[] args) {
        GoldAKGun akGun = new GoldAKGun("黄金AK",10);
        new Thread(new Sniper(akGun),"狙击手->顺溜").start();
        new Thread(new Sniper(akGun),"狙击手->二嘎").start();
        //new Thread(new Deputy(akGun),"备弹手->二雷").start();
        new Thread(new Deputy(akGun),"备弹手->二毛").start();
        new Thread(new Deputy(akGun),"备弹手->铁蛋").start();
        new Thread(new Deputy(akGun),"备弹手->大柱").start();
    }


    public static class GoldAKGun{
        private String gunName = "AK";    //默认名字AK
        private Integer bollet = 0;     //默认备弹 0 发

        public GoldAKGun(String gunName, Integer bollet) {
            this.gunName = gunName;
            this.bollet = bollet;
        }

        public synchronized void putBollet(String name){
            try {
                while (bollet>=20){
                    System.out.println(name + "->发现["+ gunName +"]的子弹是满的 !");
                    this.wait();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            bollet++;
            System.out.println(name + "->成功拿起["+ gunName +"]装入一枚子弹,当前子弹数目:" + bollet);
            this.notifyAll();
        }

        public synchronized void shotGirld(String name){
            try {
                while (bollet<=0){
                    System.out.println(name + "->发现["+ gunName +"]的弹夹是空的 !");
                    this.wait();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }

            bollet--;
            System.out.println(name + "->扣动["+ gunName +"]板机,打了个鸟儿,当前子弹数目:" + bollet);
            this.notifyAll();
        }

    }


    public static class Sniper implements Runnable{

        GoldAKGun ak47;

        public Sniper(GoldAKGun ak47){
            this.ak47 = ak47;
        }

        @Override
        public void run(){
            for (;;) {
                sleep(500);
                ak47.shotGirld(Thread.currentThread().getName());
            }
        }
    }

    public static class Deputy implements Runnable{

        GoldAKGun ak47;

        public Deputy(GoldAKGun ak47){
            this.ak47 = ak47;
        }

        @Override
        public void run(){
            for (;;) {
                sleep(1000);
                ak47.putBollet(Thread.currentThread().getName());
            }
        }
    }

    public static void sleep(Integer millis){
        try {
            Thread.sleep(millis);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

总结描述

    synchronized、wait、notifyAll在常用的java开发框架中,多次出现,需要深入的研究一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章