1. 程式人生 > >多執行緒解決熊吃蜂蜜問題

多執行緒解決熊吃蜂蜜問題

一、問題

有n只蜜蜂和一隻飢餓的熊。他們共享一罐蜂蜜。這個罐子最初是空的;它的容量是蜜蜂的一半。熊睡到罐子裡的蜂蜜滿了,然後把所有的蜂蜜都吃了,然後再繼續睡覺。每隻蜜蜂都要反覆地收集一份蜂蜜,並把它放進罐子裡蜜蜂填滿罐子,喚醒了熊。

二、程式碼

public class BearAndHoneybees {
    //罐子
    public static class Pot {
        private int start = 0;
        private int Max;
        private Pot(int n){
            Max = n/2;
        }
    }
    //蜜蜂
    public static class Bee extends Thread{
        private Pot pot;
        public Bee(Pot pot){
            this.pot=pot;
        }
        @Override
        public void run() {
            for (;;)
                try {
                    synchronized (pot) {
                        while (pot.start == pot.Max) {
                            try {
                                pot.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        pot.start++;
                        pot.notifyAll();
                    }
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
    //熊
    public static class Bear extends Thread{
        private Pot pot;
        public Bear(Pot pot){
            this.pot=pot;
        }
        @Override
        public void run() {
            for (;;){
                synchronized(pot){
                    while (pot.start < pot.Max) {
                        try {
                            pot.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    pot.start=0;
                    pot.notifyAll();
                }
            }
        }
    }

    public static void main(String[] args) {
        int n=100;
        Pot pot=new Pot(n);
        for (int i = 0; i <n ; i++) {
            new Bee(pot).start();
        }
        new Bear(pot).start();
    }
}

三、求其他解法

類似方案一(XX提供)

public class Test {

    private static final Integer potLength = 10;

    public static void main(String[] args) {
        HoneyPot honeyPot = new HoneyPot(potLength);
        honeyPot.start();
        for (int i = 0; i < 10000; i++) {
            honeyPot.putHoney(new Object());
            System.out.println("密封放置蜂蜜,長度:"+honeyPot.getPot().size());
        }

        System.out.println("跑完了,中斷執行緒...");
        honeyPot.interrupt();
    }
}

class HoneyPot extends Thread {


    private List<Object> pot = new ArrayList<>();

    private Integer potLength;

    final ReentrantLock lock;

    private final Condition notEmpty;

    private final Condition notFull;

    HoneyPot(Integer potLength) {
        this.potLength = potLength;
        lock = new ReentrantLock();
        notEmpty = lock.newCondition();
        notFull = lock.newCondition();
    }

    /**
     * 密封放置蜂蜜
     *
     * @param object 蜂蜜
     */
    public void putHoney(Object object) {
        try {
            lock.lockInterruptibly();
            if (pot.size() >= potLength) {
                notEmpty.signal();
                notFull.await();
            }
            pot.add(object);
        } catch (Exception e) {
            System.out.println("putHoney異常");
        } finally {
            lock.unlock();
        }
    }


    @Override
    public void run() {
        while (true) {
            try {
                lock.lockInterruptibly();
                if (pot.size() < potLength) {
                    notEmpty.await();
                } else {
                    Iterator<Object> its = pot.iterator();
                    while (its.hasNext()) {
                        its.next();
                        if (pot.size() < (potLength / 2)) {
                            break;
                        }
                        its.remove();
                    }
                    System.out.println("熊吃掉一半蜂蜜,長度:"+pot.size());
                    notFull.signal();
                }
            } catch (InterruptedException e) {
                System.out.println("takeHoney異常");
            } finally {
                lock.unlock();
            }
        }
    }

    public List<Object> getPot() {
        return pot;
    }
}

類似方案二

public class HoneyJar {
    //罐子最大容量
    private final int JAR_MAX_VOL = 100;
    //罐子當前容量
    private volatile int jar_cur_vol = 0;

    //罐子鎖
    private ReentrantLock lock = new ReentrantLock();
    //罐子條件--滿
    private Condition isFull = lock.newCondition();
    //罐子條件--空
    private Condition isEmpty = lock.newCondition();

    //罐子蜂蜜增加
    public void honeyIncrease(){
        try {
            lock.lockInterruptibly();

            //罐子滿時通知熊吃蜂蜜並且使蜜蜂等待裝蜂蜜
            if(jar_cur_vol >= JAR_MAX_VOL){
                isFull.signal();
                isEmpty.await();
            }else{
                Thread.sleep(100);
                jar_cur_vol++;
                System.out.println(Thread.currentThread().getName() + "號蜜蜂將蜂蜜裝入罐子,當前罐子蜂蜜容量:" + jar_cur_vol);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    //罐子蜂蜜減少
    public void honeyDecrease(){
        try {
            lock.lockInterruptibly();

            //罐子空時通知熊等待並且使蜜蜂開始裝蜂蜜
            if(jar_cur_vol == 0){
                isFull.await();
                isEmpty.signalAll();
            }else{
                System.out.println("熊正在吃蜂蜜....");
                Thread.sleep(1000);
                do{
                    jar_cur_vol--;
                }while(jar_cur_vol > 0);
                System.out.println("熊已經吃光蜂蜜....");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}
public class Bee implements Runnable{
    private HoneyJar jar;

    public Bee(HoneyJar jar){
        this.jar = jar;
    }
    @Override
    public void run() {
        //蜜蜂向罐子裝蜂蜜
        for(;;){
            jar.honeyIncrease();
        }
    }
}
public class Bear implements Runnable{
    private HoneyJar jar;

    public Bear(HoneyJar jar){
        this.jar = jar;
    }

    @Override
    public void run() {
        //熊吃蜂蜜
        for(;;){
            jar.honeyDecrease();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        HoneyJar hj=new HoneyJar();
        for (int i = 0; i <10 ; i++) {
            new Thread(new Bee(hj),i+"號bee").start();
        }
        new Thread(new Bear(hj)).start();
    }
}

四、參考解法