生产消费线程讲解例子

在网上找到一个生产消费线程的例子,是马士兵写的据说,我把代码拷贝出来运行了一下,我们来看看有什么问题,先来看看原来的代码:

package com.darren.test.thread;

public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        new Thread(p).start();
        new Thread(p).start();
        new Thread(p).start();
        new Thread(c).start();
    }
}

/**
 * 定义一个WoTou类 ,在类中有id以标记是哪个窝头,重写了toString方法
 */
class WoTou {
    private int id;

    WoTou(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "WoTou : " + id;
    }
}

/**
 * 定义一个篮子的对象,用于装WoTou
 * 
 * push方法,用于装WoTou
 * 
 * pop方法,用于吃WoTou
 */
class SyncStack {
    private int index = 0;
    private WoTou[] arrWT = new WoTou[6];

    /**
     * wait()只有在锁定(synchronized)的时候才能使用
     */

    // push用于装WoTou,当WoTou数达到6时wait()休息
    public synchronized void push(WoTou wt) {
        while (index == arrWT.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 唤醒wait()
        this.notifyAll();
        arrWT[index] = wt;
        index++;
    }

    // pop用于吃WoTou,当WoTou数为0时wait()
    public synchronized WoTou pop() {
        while (index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        return arrWT[index];
    }
}

/**
 * 实现Runnable接口,实现run方法的Producer类,一个对象只生产20个WoTou
 */
class Producer implements Runnable {
    private SyncStack ss = null;

    Producer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
            System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int) (Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 实现Runnable接口,实现run方法的Consumer类,一个对象只消费20个WoTou
 */
class Consumer implements Runnable {
    private SyncStack ss = null;

    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = ss.pop();
            System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


运行结果是这样的:

生产了:WoTou : 0
生产了:WoTou : 0
消费了: WoTou : 0
生产了:WoTou : 0
生产了:WoTou : 1
生产了:WoTou : 1
生产了:WoTou : 2
生产了:WoTou : 1
消费了: WoTou : 1
生产了:WoTou : 2
消费了: WoTou : 2
生产了:WoTou : 3
消费了: WoTou : 3
生产了:WoTou : 4
消费了: WoTou : 4
生产了:WoTou : 5
生产了:WoTou : 6
消费了: WoTou : 5
生产了:WoTou : 7
消费了: WoTou : 6
生产了:WoTou : 8
消费了: WoTou : 7
生产了:WoTou : 9
消费了: WoTou : 8
消费了: WoTou : 9
生产了:WoTou : 10
生产了:WoTou : 11
消费了: WoTou : 10
消费了: WoTou : 11
生产了:WoTou : 12
消费了: WoTou : 12
生产了:WoTou : 2
生产了:WoTou : 3
消费了: WoTou : 2
消费了: WoTou : 3
生产了:WoTou : 4
消费了: WoTou : 4
生产了:WoTou : 13
消费了: WoTou : 13
生产了:WoTou : 14
消费了: WoTou : 14
生产了:WoTou : 3
生产了:WoTou : 4
消费了: WoTou : 3
生产了:WoTou : 5
消费了: WoTou : 4
分析一下,有三个生产线程,一个消费线程,最终没有消费完,想必马老师有点懒,id号都一样,也不好看出开,稍微改动一点看看,先把生产线程改为一个,再加点log看看情况,帮助理解:

package com.darren.test.thread;

public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        // new Thread(p).start();
        // new Thread(p).start();
        new Thread(p).start();
        new Thread(c).start();
    }
}

/**
 * 定义一个WoTou类 ,在类中有id以标记是哪个窝头,重写了toString方法
 */
class WoTou {
    private int id;

    WoTou(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "WoTou : " + id;
    }
}

/**
 * 定义一个篮子的对象,用于装WoTou
 * 
 * push方法,用于装WoTou
 * 
 * pop方法,用于吃WoTou
 */
class SyncStack {
    private int index = 0;
    private WoTou[] arrWT = new WoTou[6];

    /**
     * wait()只有在锁定(synchronized)的时候才能使用
     */

    // push用于装WoTou,当WoTou数达到6时wait()休息
    public synchronized void push(WoTou wt) {
        while (index == arrWT.length) {
            try {
                System.out.println("等待消费!");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 唤醒wait()
        this.notifyAll();
        arrWT[index] = wt;
        index++;
    }

    // pop用于吃WoTou,当WoTou数为0时wait()
    public synchronized WoTou pop() {
        while (index == 0) {
            try {
                System.out.println("等待生产!");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        return arrWT[index];
    }
}

/**
 * 实现Runnable接口,实现run方法的Producer类,一个对象只生产20个WoTou
 */
class Producer implements Runnable {
    private SyncStack ss = null;

    Producer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
            System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int) (Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 实现Runnable接口,实现run方法的Consumer类,一个对象只消费20个WoTou
 */
class Consumer implements Runnable {
    private SyncStack ss = null;

    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = ss.pop();
            System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
消费了: WoTou : 0
生产了:WoTou : 0
生产了:WoTou : 1
生产了:WoTou : 2
消费了: WoTou : 2
生产了:WoTou : 3
生产了:WoTou : 4
消费了: WoTou : 4
生产了:WoTou : 5
消费了: WoTou : 5
生产了:WoTou : 6
生产了:WoTou : 7
生产了:WoTou : 8
生产了:WoTou : 9
等待消费!
生产了:WoTou : 10
消费了: WoTou : 9
等待消费!
消费了: WoTou : 10
生产了:WoTou : 11
等待消费!
消费了: WoTou : 11
生产了:WoTou : 12
等待消费!
消费了: WoTou : 12
生产了:WoTou : 13
等待消费!
消费了: WoTou : 13
生产了:WoTou : 14
等待消费!
消费了: WoTou : 14
生产了:WoTou : 15
等待消费!
消费了: WoTou : 15
生产了:WoTou : 16
等待消费!
生产了:WoTou : 17
消费了: WoTou : 16
等待消费!
消费了: WoTou : 17
生产了:WoTou : 18
等待消费!
消费了: WoTou : 18
生产了:WoTou : 19
消费了: WoTou : 19
消费了: WoTou : 8
消费了: WoTou : 7
消费了: WoTou : 6
消费了: WoTou : 3
消费了: WoTou : 1
这下是不是清楚多了,最后也全部消费完了,还能看到有等待的情况,这种情况看明白以后,我们再改动点,去看明白马老师写的代码:

package com.darren.test.thread;

public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p1 = new Producer(ss, 1);
        Producer p2 = new Producer(ss, 2);
        Producer p3 = new Producer(ss, 3);
        Consumer c = new Consumer(ss);
        new Thread(p1).start();
        new Thread(p2).start();
        new Thread(p3).start();
        new Thread(c).start();
    }
}

/**
 * 定义一个WoTou类 ,在类中有id以标记是哪个窝头,重写了toString方法
 */
class WoTou {
    /**
     * 窝头ID
     */
    private int id;
    /**
     * 生产者ID
     */
    private int producerId;

    WoTou(int id, int producerId) {
        this.id = id;
        this.producerId = producerId;
    }

    @Override
    public String toString() {
        return "WoTou [窝头ID=" + id + ", 生产者ID=" + producerId + "]";
    }
}

/**
 * 定义一个篮子的对象,用于装WoTou
 * 
 * push方法,用于装WoTou
 * 
 * pop方法,用于吃WoTou
 */
class SyncStack {
    private int index = 0;
    private WoTou[] arrWT = new WoTou[6];

    /**
     * wait()只有在锁定(synchronized)的时候才能使用
     */

    // push用于装WoTou,当WoTou数达到6时wait()休息
    public synchronized void push(WoTou wt) {
        while (index == arrWT.length) {
            try {
                System.out.println("等待消费!");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 唤醒wait()
        this.notifyAll();
        arrWT[index] = wt;
        index++;
    }

    // pop用于吃WoTou,当WoTou数为0时wait()
    public synchronized WoTou pop() {
        while (index == 0) {
            try {
                System.out.println("等待生产!");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        return arrWT[index];
    }
}

/**
 * 实现Runnable接口,实现run方法的Producer类,一个对象只生产20个WoTou
 */
class Producer implements Runnable {
    /**
     * 生产者ID
     */
    private int id;
    private SyncStack ss = null;

    Producer(SyncStack ss, int id) {
        this.ss = ss;
        this.id = id;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = new WoTou(i, id);
            ss.push(wt);
            System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int) (Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 实现Runnable接口,实现run方法的Consumer类,一个对象只消费20个WoTou
 */
class Consumer implements Runnable {
    private SyncStack ss = null;

    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = ss.pop();
            System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
生产了:WoTou [窝头ID=0, 生产者ID=1]
生产了:WoTou [窝头ID=0, 生产者ID=3]
生产了:WoTou [窝头ID=0, 生产者ID=2]
消费了: WoTou [窝头ID=0, 生产者ID=3]
生产了:WoTou [窝头ID=1, 生产者ID=2]
生产了:WoTou [窝头ID=1, 生产者ID=1]
生产了:WoTou [窝头ID=2, 生产者ID=1]
生产了:WoTou [窝头ID=1, 生产者ID=3]
等待消费!
等待消费!
等待消费!
等待消费!
等待消费!
生产了:WoTou [窝头ID=2, 生产者ID=2]
消费了: WoTou [窝头ID=1, 生产者ID=3]
等待消费!
消费了: WoTou [窝头ID=2, 生产者ID=2]
生产了:WoTou [窝头ID=3, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=3, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=4, 生产者ID=2]
等待消费!
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=4, 生产者ID=2]
生产了:WoTou [窝头ID=5, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=5, 生产者ID=2]
生产了:WoTou [窝头ID=6, 生产者ID=2]
等待消费!
消费了: WoTou [窝头ID=6, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=7, 生产者ID=2]
等待消费!
等待消费!
等待消费!
等待消费!
生产了:WoTou [窝头ID=8, 生产者ID=2]
消费了: WoTou [窝头ID=7, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=3, 生产者ID=1]
消费了: WoTou [窝头ID=8, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=3, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=4, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=4, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=5, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=5, 生产者ID=1]
生产了:WoTou [窝头ID=6, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=6, 生产者ID=1]
生产了:WoTou [窝头ID=7, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=7, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=8, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=8, 生产者ID=1]
生产了:WoTou [窝头ID=9, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=10, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=9, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=11, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=10, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=12, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=11, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=12, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=13, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=13, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=14, 生产者ID=1]
等待消费!
很清楚的看出消费者消费了不同生产者生产的窝头,想必这才是马老师想要表达的意思

仔细看看,这个结果好像还不够热闹,不如再加一个消费线程看看:

    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p1 = new Producer(ss, 1);
        Producer p2 = new Producer(ss, 2);
        Producer p3 = new Producer(ss, 3);
        Consumer c = new Consumer(ss);
        new Thread(p1).start();
        new Thread(p2).start();
        new Thread(p3).start();
        new Thread(c).start();
        new Thread(c).start();
    }
生产了:WoTou [窝头ID=0, 生产者ID=1]
消费了: WoTou [窝头ID=0, 生产者ID=3]
生产了:WoTou [窝头ID=0, 生产者ID=3]
生产了:WoTou [窝头ID=0, 生产者ID=2]
消费了: WoTou [窝头ID=0, 生产者ID=2]
生产了:WoTou [窝头ID=1, 生产者ID=1]
生产了:WoTou [窝头ID=1, 生产者ID=3]
生产了:WoTou [窝头ID=2, 生产者ID=1]
生产了:WoTou [窝头ID=1, 生产者ID=2]
生产了:WoTou [窝头ID=3, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=3, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=4, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=4, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=5, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=5, 生产者ID=1]
生产了:WoTou [窝头ID=6, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=6, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=2, 生产者ID=2]
生产了:WoTou [窝头ID=2, 生产者ID=3]
消费了: WoTou [窝头ID=2, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=2, 生产者ID=3]
等待消费!
等待消费!
生产了:WoTou [窝头ID=7, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=7, 生产者ID=1]
生产了:WoTou [窝头ID=3, 生产者ID=2]
等待消费!
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=3, 生产者ID=2]
生产了:WoTou [窝头ID=4, 生产者ID=2]
等待消费!
等待消费!
消费了: WoTou [窝头ID=4, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=5, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=6, 生产者ID=2]
消费了: WoTou [窝头ID=5, 生产者ID=2]
等待消费!
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=6, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=7, 生产者ID=2]
等待消费!
等待消费!
消费了: WoTou [窝头ID=7, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=8, 生产者ID=2]
生产了:WoTou [窝头ID=3, 生产者ID=3]
等待消费!
消费了: WoTou [窝头ID=8, 生产者ID=2]
等待消费!
等待消费!
生产了:WoTou [窝头ID=9, 生产者ID=2]
消费了: WoTou [窝头ID=3, 生产者ID=3]
消费了: WoTou [窝头ID=1, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=4, 生产者ID=3]
等待消费!
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=9, 生产者ID=2]
生产了:WoTou [窝头ID=10, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=11, 生产者ID=2]
消费了: WoTou [窝头ID=10, 生产者ID=2]
等待消费!
等待消费!
消费了: WoTou [窝头ID=11, 生产者ID=2]
生产了:WoTou [窝头ID=5, 生产者ID=3]
等待消费!
等待消费!
等待消费!
生产了:WoTou [窝头ID=12, 生产者ID=2]
消费了: WoTou [窝头ID=5, 生产者ID=3]
等待消费!
等待消费!
等待消费!
生产了:WoTou [窝头ID=8, 生产者ID=1]
消费了: WoTou [窝头ID=12, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=8, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=13, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=14, 生产者ID=2]
消费了: WoTou [窝头ID=13, 生产者ID=2]
等待消费!
等待消费!
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=14, 生产者ID=2]
生产了:WoTou [窝头ID=15, 生产者ID=2]
等待消费!
等待消费!
消费了: WoTou [窝头ID=15, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=16, 生产者ID=2]
消费了: WoTou [窝头ID=16, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=9, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=17, 生产者ID=2]
消费了: WoTou [窝头ID=9, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=17, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=10, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=10, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=11, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=11, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=12, 生产者ID=1]
等待消费!
等待消费!
消费了: WoTou [窝头ID=12, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=13, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=13, 生产者ID=1]
生产了:WoTou [窝头ID=18, 生产者ID=2]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=18, 生产者ID=2]
等待消费!
生产了:WoTou [窝头ID=19, 生产者ID=2]
生产了:WoTou [窝头ID=6, 生产者ID=3]
等待消费!
消费了: WoTou [窝头ID=19, 生产者ID=2]
消费了: WoTou [窝头ID=6, 生产者ID=3]
生产了:WoTou [窝头ID=14, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=15, 生产者ID=1]
消费了: WoTou [窝头ID=14, 生产者ID=1]
等待消费!
等待消费!
生产了:WoTou [窝头ID=16, 生产者ID=1]
等待消费!
消费了: WoTou [窝头ID=15, 生产者ID=1]
等待消费!
生产了:WoTou [窝头ID=17, 生产者ID=1]
消费了: WoTou [窝头ID=16, 生产者ID=1]
等待消费!
等待消费!
等待消费!
消费了: WoTou [窝头ID=17, 生产者ID=1]
生产了:WoTou [窝头ID=18, 生产者ID=1]
等待消费!
这下热闹了吧,最后一段就当娱乐吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值