首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

以填酒、饮酒为例说明线程同步:阻塞、死锁、非阻塞、Notify/Wait机制

2013-03-13 
以填酒、喝酒为例说明线程同步:阻塞、死锁、非阻塞、Notify/Wait机制一个填酒线程,一个喝酒线程对一个酒杯轮流

以填酒、喝酒为例说明线程同步:阻塞、死锁、非阻塞、Notify/Wait机制
一个填酒线程,一个喝酒线程对一个酒杯轮流进行操作。

阻塞、死锁

package player.kent.chen.learn.threads.notify;/** * 酒杯 *  * @author kent 2013-3-11下午4:34:30 */public class Cup {    private volatile boolean empty = true;    /**     * 填酒,阻塞式地     *      * @author kent 2013-3-11下午4:59:33     */    public synchronized void fill() {        while (!empty) { //若酒杯不为空则等待            ;        }        doFill();    }    /**     * 清空酒杯,阻塞式地     *      * @author kent 2013-3-11下午4:59:50     */    public synchronized void drain() {        while (empty) {//若酒杯为空则等待            ;        }        doDrain();    }     private void doFill() {        System.out.println(Thread.currentThread().getName() + " filled the cup");        empty = false;    }    private void doDrain() {        System.out.println(Thread.currentThread().getName() + " drained the cup");        empty = true;    }}


package player.kent.chen.learn.threads.notify;/** * 酒吧工作人员,无休止地填酒 (阻塞式地) */public class BlockBartender implements Runnable {    private Cup cup;    /**     * @param cup     */    public BlockBartender(Cup cup) {        super();        this.cup = cup;    }    public void run() {        while (true) {            cup.fill();        }    }}




package player.kent.chen.learn.threads.notify;/** * 喝酒的人,不停地喝酒(阻塞式地) *  * @author kent 2013-3-11下午5:02:34 */public class BlockDrinker implements Runnable {    private Cup cup;    /**     * @param cup     */    public BlockDrinker(Cup cup) {        super();        this.cup = cup;    }    /**     * @author kent 2013-3-11下午5:02:56     */    public void run() {        while (true) {            cup.drain();        }    }}



package player.kent.chen.learn.threads.notify;public class CupMain {    public static void main(String[] args) {        Cup cup = new Cup();        Thread bartenderThread = new Thread(new BlockBartender(cup), "bartender");        Thread drinkerThread = new Thread(new BlockDrinker(cup), "drinker");        bartenderThread.start();        drinkerThread.start();        /**         * 执行时将以死锁告终。 <br/>         * 1. 假设bartender先执行并先获得锁 <br/>         * 2. bartender填酒, 然后empty=false <br/>         * 3. 然后bartender陷入等待,直到drinker把empty置为true <br/>         * 4. 同时bartender一直持有锁 <br/>         * 5. drinker无法将empty置为false, 因为它在执行drain()时发现自己拿不到锁 <br/>         * 6. 结果,bartender要drinker把empty置为true后才能释放锁,         * 而drinker要bartender释放锁后才能将empty置为true。结果就是死锁         */    }}



非阻塞、无死锁
package player.kent.chen.learn.threads.notify;/** * 酒杯 *  * @author kent 2013-3-11下午4:34:30 */public class Cup {    private volatile boolean empty = true;       /**     * 非阻塞式地填酒     *      * @author kent 2013-3-11下午4:59:59     */    public synchronized void tryFill() {        if (empty) {            doFill();        }    }    /**     * 非阻塞式地清空酒杯     *      * @author kent 2013-3-11下午5:00:12     */    public synchronized void tryDrain() {        if (!empty) {            doDrain();        }    }    private void doFill() {        System.out.println(Thread.currentThread().getName() + " filled the cup");        empty = false;    }    private void doDrain() {        System.out.println(Thread.currentThread().getName() + " drained the cup");        empty = true;    }}




package player.kent.chen.learn.threads.notify;/** * 酒吧工作人员,无休止地填酒 (非阻塞式地) */public class NonBlockBartender implements Runnable {    private Cup cup;    /**     * @param cup     */    public NonBlockBartender(Cup cup) {        super();        this.cup = cup;    }    public void run() {        while (true) {            cup.tryFill();        }    }}



package player.kent.chen.learn.threads.notify;/** * 喝酒的人,不停地喝酒(非阻塞式地) *  * @author kent 2013-3-11下午5:02:34 */public class NonBlockDrinker implements Runnable {    private Cup cup;    /**     * @param cup     */    public NonBlockDrinker(Cup cup) {        super();        this.cup = cup;    }    /**     * @author kent 2013-3-11下午5:02:56     */    public void run() {        while (true) {            cup.tryDrain();        }    }}



package player.kent.chen.learn.threads.notify;public class CupMain {       public static void main(String[] args) {        Cup cup = new Cup();        Thread bartenderThread = new Thread(new NonBlockBartender(cup), "bartender");        Thread drinkerThread = new Thread(new NonBlockDrinker(cup), "drinker");        bartenderThread.start();        drinkerThread.start();        /**         * 执行时将出现预期的结果:一填一喝,一喝一填 <br/>         * 1. 假设bartender先执行并先获得锁 <br/>         * 2. bartender填酒, 然后empty=false <br/>         * 3. 然后bartender再试着填酒,发现empty仍是false,所以退出tryFill()方法并释放锁<br/>         * 4. 可能重复第3步若干次 <br/>         * 5. drinker在某个时机获得锁,然后empty=true<br/>         * 6. 然后drinker再试着喝酒,发现empty仍是true,所以退出tryDrain()方法并释放锁<br/>         * 7. 可能重复第6步若干次<br/>         * 8. bartender在某个时机获得锁,然后回到第2步。。。         * 这种机制的缺点是里面的while循环会不停轮询empty状态,造成cpu浪费          */    }   }


使用Notify-Wait机制,避免轮询
package player.kent.chen.learn.threads.notify;/** * 酒杯 *  * @author kent 2013-3-11下午4:34:30 */public class Cup {    private volatile boolean empty = true;     /**     * 填酒,使用Notify-Wait机制     *      * @author kent 2013-3-11下午4:59:33     * @throws InterruptedException     */    public synchronized void fillWithNw() throws InterruptedException {        while (!empty) { //若酒杯不为空则等待并释放锁            wait();        }        doFill();        notifyAll(); //把等待中的其他线程唤醒(实际就是清空酒杯的线程)    }    /**     * 清空酒杯,使用Notify-Wait机制     *      * @author kent 2013-3-11下午4:59:50     * @throws InterruptedException     */    public synchronized void drainWithNw() throws InterruptedException {        while (empty) {//若酒杯为空则等待并释放锁            wait();        }        doDrain();        notifyAll(); //把等待中的其他线程唤醒(实际就是填酒的线程)    }    private void doFill() {        System.out.println(Thread.currentThread().getName() + " filled the cup");        empty = false;    }    private void doDrain() {        System.out.println(Thread.currentThread().getName() + " drained the cup");        empty = true;    }}



package player.kent.chen.learn.threads.notify;/** * 酒吧工作人员,无休止地填酒 (利用Notify + Wait机制与喝酒者互动) */public class NwBartender implements Runnable {    private Cup cup;    /**     * @param cup     */    public NwBartender(Cup cup) {        super();        this.cup = cup;    }    public void run() {        while (true) {            try {                cup.fillWithNw();            } catch (InterruptedException e) {                //do nothing            }        }    }}



package player.kent.chen.learn.threads.notify;/** * 喝酒的人,不停地喝酒(利用Notify + Wait机制与酒吧招待互动) *  * @author kent 2013-3-11下午5:02:34 */public class NwDrinker implements Runnable {    private Cup cup;    /**     * @param cup     */    public NwDrinker(Cup cup) {        super();        this.cup = cup;    }    /**     * @author kent 2013-3-11下午5:02:56     */    public void run() {        while (true) {            try {                cup.drainWithNw();            } catch (InterruptedException e) {                //do nothing            }        }    }}


package player.kent.chen.learn.threads.notify;public class CupMain {    public static void main(String[] args) {        Cup cup = new Cup();        Thread bartenderThread = new Thread(new NwBartender(cup), "bartender");        Thread drinkerThread = new Thread(new NwDrinker(cup), "drinker");        bartenderThread.start();        drinkerThread.start();    }        /**         * 执行时将出现预期的结果,而且没有CPU不会空转         */    }

热点排行