多线程案例:生产者和消费者



以继承Thread实现:

           

package example;

/**
* 所有synchronized方法持有同一把this锁,
* synchronized方法执行到wait()时放锁,
* 让其他线程可以进入相应的synchronized方法
* @author 姚丽辉
*/
public class Producter_Consumer {
private int     size = 5;      //容器大小
private int     remain = size;      //剩余空间
private int[] common = new int[size];//容器,该信号量用于同步生产者和消费者

private synchronized void product(int i) throws InterruptedException {
     if (remain > 0) {
      notify();//通知生产者继续
     }
     common[i % size] = i;
     remain--;
     System.out.println("product:" + i);
     if (remain == 0) {
      System.out.println("product wait");
      wait();//让生产者等待
     }
}

private synchronized void consume(int i) throws InterruptedException {
     if ((size - remain) > 0) {
      notify();//通知消费者继续
     }
     System.out.println("consume:" + common[i % size]);
     remain++;
     if (remain == size) {
      System.out.println("consume wait");
      wait();//让消费者等待
     }
}

class Producter extends Thread {
     public void run() {
      for (int i = 1; true; i++) {
       try {
        product(i);
        sleep((int) (Math.random() * 5000));
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }
}

class Consumer extends Thread {
     public void run() {
      for (int i = 1; true; i++) {
       try {
        consume(i);
        sleep((int) (Math.random() * 5000));
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }
}

private void start() {
     Producter p = new Producter();
     Consumer c = new Consumer();
     p.start();
     c.start();
}

public static void main(String[] args) {
     Producter_Consumer m = new Producter_Consumer();
     m.start();
}

}











实现Runnable接口


1。生产和消费的产品抽象类

//预留

public abstract class Product {
    
    public String name;
    public abstract String toString();

}


2。一个具体的产品类

public class AProduct extends Product {

    public AProduct(String pname) {
        super();
        name = pname;
        // TODO Auto-generated constructor stub
    }

    public String toString() {
        // TODO Auto-generated method stub
        return name;
    }

}


3。容器类(仓库)

import java.util.ArrayList;

/*
 * 存放生产者和消费者的产品队列
 * */

public class Container {

    private ArrayList arrList = new ArrayList();

    private int LENGTH = 10;

    public boolean isFull() {
        return arrList.size() == LENGTH;
    }

    public boolean isEmpty() {
        return arrList.isEmpty();
    }

    /* 如果此处不加synchronized锁,那么也可以再调用push的地方加锁
    * 既然此处加了锁,那么再别的地方可以不加锁
    */

    public synchronized void push(Object o) {
        arrList.add(o);
    }

    // 如果此处不加synchronized锁,那么也可以再调用push的地方加锁

    public synchronized Object pop() {
        Object lastOne = arrList.get(arrList.size() - 1);
        arrList.remove(arrList.size() - 1);

        return lastOne;
    }
}


4。休息一会,生产者和消费者都要休息,因此作为抽象基类


public abstract class Sleep {

    public void haveASleep() throws InterruptedException {

        Thread.sleep((long) (Math.random() * 3000));
    }

}

// sleep让出cpu时间给其他线程执行.也许你会问,既然我已经wait了,为什么还要sleep?

 // wait()的作用就是阻塞当前线程并且释放对象的
给别人(一般是等待队列中的第一个线程)

 // Thead.sleep()也是阻塞当前线程,但不释放锁。

 // sleep()方法是使线程停止一段时间的方法。

 // 在sleep 时间间隔期满后,线程不一定立即恢复执行。

 // 这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非 (a)“醒来”的线程具有更高的优先级。

 // (b)正在运行的线程因为其它原因而阻塞。 wait()是线程交互时,如果线程对一个同步对象x

 // 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。

 // 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。

 // waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized

 

/*
 * 消费者线程
 * */

public class Consumer extends Sleep implements Runnable {
    private Container contain = null;

    public Consumer(Container contain) {
        super();
        this.contain = contain;
    }

    public void run() {
        // TODO Auto-generated method stub

        while (true) {
            synchronized (contain) {
                while (contain.isEmpty()) {
                    try {
                        contain.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block

                        e.printStackTrace();
                    }
                }
            }
            consume();//消费

            try {
                haveASleep();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block

                e.printStackTrace();
            }
            synchronized (contain) {
                contain.notify();
            }
        }
    }

    private void consume() {
        Product a = (AProduct) contain.pop();
        System.out.println("消费了一个产品" + a.toString());
    }
}

/*
 * 生产者线程
 * */

public class Producator extends Sleep implements Runnable {
    private Container contain = null;

    public Producator(Container contain) {
        super();
        this.contain = contain;
    }

    public void run() {
        // TODO Auto-generated method stub

        while (true) {
            synchronized (contain) {
                while (contain.isFull()) {
                    try {
                        contain.wait();// 阻塞当前线程,当前线程进入等待队列。这个时候只有等待别的线程来唤醒自己了。

                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block

                        e.printStackTrace();
                    }
                }
            }
            producer();// 生产一个产品

            try {
                haveASleep();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block

                e.printStackTrace();
            }
            synchronized (contain) {
                contain.notify();// 唤醒等待队列中正在等待的第一个线程,让其执行。

            }
        }
    }

    public void producer() {
        Product aProduct = new AProduct("pp:" + String.valueOf(Math.random()));
        System.out.println("生产了一个产品:" + aProduct.toString());
        contain.push(aProduct);
    }

}

5 写一个测试吧:

public class TestMain {

    /**
     * @param args
     */

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Container contain = new Container();
        Producator p = new Producator(contain);
        Consumer c = new Consumer(contain);
        Thread pt = new Thread(p);
        Thread ct = new Thread(c);
        pt.start();
        ct.start();
    }

}

 

 

1.生产和消费的产品抽象类:
public abstract class Product {
    public String name;
    public abstract String toString();
}

2.一个具体的产品类:

public class AProduct extends Product {
    public AProduct(String name) {
        this.name = name;
        // TODO Auto-generated constructor stub
    }
    public String toString() {
        // TODO Auto-generated method stub
        return this.name;
    }
}

3.容器类(仓库):

import java.util.ArrayList;

/*
 * 存放生产者和消费者的产品队列
 * */

public class Container {
    private ArrayList arrList = new ArrayList();
    private int LENGTH = 10;
    public boolean isFull() {
        return arrList.size()==LENGTH;
    }
    public boolean isEmpty() {
        return arrList.isEmpty();
    }

    /* 如果此处不加synchronized锁,那么也可以再调用push的地方加锁
    * 既然此处加了锁,那么再别的地方可以不加锁
    */

    public synchronized void push(Object o) {
        arrList.add(o);
    }
    // 如果此处不加synchronized锁,那么也可以再调用push的地方加锁
    public synchronized Object pop() {
        Object lastOne = arrList.get(arrList.size()- 1);
        arrList.remove(arrList.size()- 1);
        return lastOne;
    }
}

4.休息一会,生产者和消费者都要休息,因此作为抽象基类:

public abstract class Sleep {
    public void haveASleep() throws InterruptedException {
        Thread.sleep((long)(Math.random()* 3000));
    }
}

/*
 * 消费者线程
 * */

public class Consumer extends Sleep implements Runnable {
    private Container contain =null;
    public Consumer(Container contain) {
        this.contain = contain;
    }
    public void run() {
        // TODO Auto-generated method stub
        while(true) {
            synchronized(contain) {
                while(contain.isEmpty()) {
                    try{
                        contain.wait();
                    }catch(InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            consume();//消费
            try {
                haveASleep();
            }catch(InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            synchronized(contain) {
                contain.notify();
            }
        }
    }
    private void consume() {
        Product a = (AProduct)contain.pop();
        System.out.println("消费了一个产品"+ a.toString());
    }
}

/*
 * 生产者线程
 * */

public class Producator extends Sleep implements Runnable {
    private Container contain = null;
    public Producator(Container contain) {
        super();
        this.contain = contain;
    }
    public void run() {
        // TODO Auto-generated method stub
        while(true) {
            synchronized(contain) {
                while(contain.isFull()) {
                    try{
                        contain.wait();// 阻塞当前线程,当前线程进入等待队列。这个时候只有等待别的线程来唤醒自己了。
                    }catch(InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            producer();// 生产一个产品
            try {
                haveASleep();
            }catch(InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            synchronized(contain) {
                contain.notify();// 唤醒等待队列中正在等待的第一个线程,让其执行。
            }
        }
    }
    public void producer() {
        Product aProduct = new AProduct("pp:"+String.valueOf((int)(10*Math.random())));
        System.out.println("生产了一个产品:"+ aProduct.toString());
        contain.push(aProduct);
    }
}

5. 写一个测试:

public class TestMain {
    /**
     * @param args
     */

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Container contain = new Container();
        Producator p = new Producator(contain);
        Consumer c = new Consumer(contain);
        Thread pt =new Thread(p);
        Thread ct =new Thread(c);
        pt.start();
        ct.start();
    }
}

 

 

好了,看看执行结果吧:

生产了一个产品:pp:0.5010546528255287
生产了一个产品:pp:0.08173509855014827
消费了一个产品pp:0.5010546528255287
生产了一个产品:pp:0.7022996270428004
生产了一个产品:pp:0.6245814751574797
生产了一个产品:pp:0.2839979336434959
生产了一个产品:pp:0.49694821923381394
消费了一个产品pp:0.49694821923381394
生产了一个产品:pp:0.7830305503500449
消费了一个产品pp:0.7830305503500449
消费了一个产品pp:0.2839979336434959
生产了一个产品:pp:0.8563793401031702
消费了一个产品pp:0.8563793401031702
生产了一个产品:pp:0.32584165485489935
生产了一个产品:pp:0.28527005336129474
消费了一个产品pp:0.28527005336129474
生产了一个产品:pp:0.9941746668279293
消费了一个产品pp:0.9941746668279293
消费了一个产品pp:0.32584165485489935
生产了一个产品:pp:0.7338057107242784
生产了一个产品:pp:0.7582181553056575
消费了一个产品pp:0.7582181553056575
生产了一个产品:pp:0.7563821078081756
生产了一个产品:pp:0.5659487332730776
消费了一个产品pp:0.5659487332730776
生产了一个产品:pp:0.8737523015090108
消费了一个产品pp:0.8737523015090108
消费了一个产品pp:0.7563821078081756
消费了一个产品pp:0.7338057107242784
生产了一个产品:pp:0.37558043387512685
消费了一个产品pp:0.37558043387512685
生产了一个产品:pp:0.5152849555101155
消费了一个产品pp:0.5152849555101155
消费了一个产品pp:0.6245814751574797
生产了一个产品:pp:0.2839737014600726
生产了一个产品:pp:0.14867665839711486
消费了一个产品pp:0.14867665839711486
消费了一个产品pp:0.2839737014600726
生产了一个产品:pp:0.7526721181825591
消费了一个产品pp:0.7526721181825591
生产了一个产品:pp:0.7413376261101124
生产了一个产品:pp:0.6122237252752002
消费了一个产品pp:0.6122237252752002
生产了一个产品:pp:0.5506019686616669
消费了一个产品pp:0.5506019686616669
消费了一个产品pp:0.7413376261101124
消费了一个产品pp:0.7022996270428004
消费了一个产品pp:0.08173509855014827
生产了一个产品:pp:0.4210845970052677
生产了一个产品:pp:0.38826328968056667
消费了一个产品pp:0.38826328968056667
生产了一个产品:pp:0.8431303537483879
消费了一个产品pp:0.8431303537483879
消费了一个产品pp:0.4210845970052677
生产了一个产品:pp:0.34155093374925427
消费了一个产品pp:0.34155093374925427
生产了一个产品:pp:0.6344976720730141
消费了一个产品pp:0.6344976720730141
生产了一个产品:pp:0.8363082839823789
生产了一个产品:pp:0.2811236642618875
消费了一个产品pp:0.2811236642618875
生产了一个产品:pp:0.5203709922238451
消费了一个产品pp:0.5203709922238451
生产了一个产品:pp:0.33594716801656854
消费了一个产品pp:0.33594716801656854
生产了一个产品:pp:0.6769814698429393
消费了一个产品pp:0.6769814698429393
生产了一个产品:pp:0.9745584834485369
消费了一个产品pp:0.9745584834485369
生产了一个产品:pp:0.8499765864829567
消费了一个产品pp:0.8499765864829567
生产了一个产品:pp:0.6281666437831501
生产了一个产品:pp:0.7009942032367253
生产了一个产品:pp:0.6354980777267613
消费了一个产品pp:0.6354980777267613
生产了一个产品:pp:0.5343260452244308
生产了一个产品:pp:0.7760536310129287
消费了一个产品pp:0.7760536310129287
生产了一个产品:pp:0.1571400849830824
消费了一个产品pp:0.1571400849830824
生产了一个产品:pp:0.7219309859537877
消费了一个产品pp:0.7219309859537877
消费了一个产品pp:0.5343260452244308
生产了一个产品:pp:0.27212965262811006
生产了一个产品:pp:0.6767042422791443
消费了一个产品pp:0.6767042422791443
生产了一个产品:pp:0.5569267542654116
消费了一个产品pp:0.5569267542654116
生产了一个产品:pp:0.2711661616389571
消费了一个产品pp:0.2711661616389571
消费了一个产品pp:0.27212965262811006
消费了一个产品pp:0.7009942032367253
消费了一个产品pp:0.6281666437831501
生产了一个产品:pp:0.2002128062138283
生产了一个产品:pp:0.1922231902417787
消费了一个产品pp:0.1922231902417787
消费了一个产品pp:0.2002128062138283
生产了一个产品:pp:0.17966888984989626
生产了一个产品:pp:0.3671850675304076
消费了一个产品pp:0.3671850675304076
生产了一个产品:pp:0.939554979545969
消费了一个产品pp:0.939554979545969
生产了一个产品:pp:0.40458123731585616
生产了一个产品:pp:0.5295806686705823
消费了一个产品pp:0.5295806686705823
生产了一个产品:pp:0.20237224414120825
生产了一个产品:pp:0.3318491844902224
生产了一个产品:pp:0.6154098900759897
消费了一个产品pp:0.6154098900759897

……

原文地址:https://www.cnblogs.com/smallfa/p/1116864.html