java实现生产者和消费者问题的几种方式

来源:互联网 发布:php httpclient 类库 编辑:程序博客网 时间:2024/05/22 10:25

一:使用syncronized

这是最直接原始的一种实现方式:

//数据源,用来模拟生产者生产的对象public class DataSource {    //数据源--每个元素都是时间类型    private List<Date> data;    //设置数据源大小    private int maxSize;    public DataSource() {        this.data = new LinkedList<>();        this.maxSize = 10;    }    //初始化数据源方法-set    public synchronized void set(){        //如果数据源中的数据达到最大值,则让其等待        while (data.size()==maxSize){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        data.add(new Date());        System.out.printf("Set: %d.\n",data.size());        //在方法的尾部,调用notifyAll()方法来唤醒,所有在wait()方法上等待的线程        notifyAll();    }    public synchronized void get(){        //如果数据源中没有数据,则让其等待        while (data.size()==0){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.printf("Get: %d: %s .\n",data.size(),((LinkedList<?>)data).poll());    }}
//生产者public class Producer implements Runnable {    private DataSource dataSource;    public Producer(DataSource dataSource) {        this.dataSource = dataSource;    }    @Override    public void run() {        for (int i = 0; i < 1000; i++) {            dataSource.set();        }    }}
//消费者public class Consumer implements Runnable {    private DataSource dataSource;    public Consumer(DataSource dataSource) {        this.dataSource = dataSource;    }    @Override    public void run() {        for (int i = 0; i < 100; i++) {            dataSource.get();        }    }}
//测试类public class Main {    public static void main(String[] args) {        DataSource dataSource = new DataSource();        Thread producerThreads[] = new Thread[3];        Thread consumerThreads[] = new Thread[4];        for (int i = 0; i < 3; i++) producerThreads[i] = new Thread(new Producer(dataSource));        for (int i = 0; i < 4; i++) consumerThreads[i] = new Thread(new Consumer(dataSource));        for (int i = 0; i < 3; i++) producerThreads[i].start();        for (int i = 0; i < 4; i++) consumerThreads[i].start();    }}

二:使用Lock和Condition

lock是实现java同步的另外一种方式,使用lock比syncronized更加灵活。一个锁可能伴随着多个条件,这些条件在condition接口中。
我们将上面代码中DataSource类修改一下:

 //数据源--每个元素都是时间类型    private List<Date> data;    //设置数据源大小    private int maxSize;    private Condition add;    private Condition sub;    private Lock lock;    public DataSource() {        this.data = new LinkedList<>();        this.maxSize = 10;        lock = new ReentrantLock();        add = lock.newCondition();        sub = lock.newCondition();    }    //初始化数据源方法-set    public void set(){        //获取锁        lock.lock();        try{            //如果数据源中的数据达到最大值,则让其等待            while (data.size()==maxSize){            //注意,这里是await,wait()和notify()必须在synchronized的代码块中使用 因为只有在获取当前对象的锁时才能进行这两个操作 否则会报异常 而await()和signal()一般与Lock()配合使用                add.await();            }            data.add(new Date());            System.out.printf("Set: %d,%s.\n",data.size(),Thread.currentThread().getName());            //在方法的尾部,signalAll()方法来唤醒,所有在wait()方法上等待的线程            sub.signalAll();        }catch (Exception e){            e.printStackTrace();        }finally {            //释放锁            lock.unlock();        }    }    public void get(){        lock.lock();        //如果数据源中没有数据,则让其等待        try {            while (data.size()==0){                sub.await();            }            add.signalAll();            System.out.printf("Get: %d: %s .\n",data.size(),((LinkedList<?>)data).poll());        }catch (Exception e){            e.printStackTrace();        }finally {            lock.unlock();        }    }

三:使用Exchanger 类

Exchanger 类允许2个并发任务互相交换数据。Exchanger 定义了一个同步点,当两个线程到达这个点后,他们互相交换数据。也就是说,使用第一个线程的数据类型变成第二个的,然后第二个线程的数据类型变成第一个的。
只是Exchanger只能操作两个线程,所以只能在生产者和消费者中各选择一个来实现这个类。

public class Producer implements Runnable {    private List<String> buffer;    //Producer 中包含 exchanger实例    private final Exchanger<List<String>> exchanger ;    public Producer(List<String> buffer, Exchanger<List<String>> exchanger) {        this.buffer = buffer;        this.exchanger = exchanger;    }    @Override    public void run() {        for (int i = 0; i < 10; i++) {            for (int j = 0; j < 10; j++) {                String message = "Event "+((i*10)+j);                System.out.printf("Product : %s .\n",message);                buffer.add(message);            }            try {            //设置交换点                buffer = exchanger.exchange(buffer);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.printf("Producer : %d \n",buffer.size());        }    }}
public class Consumer implements Runnable {    private List<String> buffer;    private final Exchanger<List<String>> exchanger;    public Consumer(List<String> buffer, Exchanger<List<String>> exchanger) {        this.buffer = buffer;        this.exchanger = exchanger;    }    @Override    public void run() {        for (int i = 0; i < 10; i++) {            try {                buffer = exchanger.exchange(buffer);            } catch (InterruptedException e) {                e.printStackTrace();            }            for (int j = 0; j < 10; j++) {                String message = buffer.get(0);                System.out.printf("Consumer : %s .\n",message);                buffer.remove(0);            }        }    }}
public class Main {    public static void main(String[] args) {        List<String> buffer1 = new ArrayList<>();        List<String> buffer2 = new ArrayList<>();        Exchanger<List<String>> exchanger = new Exchanger<>();        Producer producer = new Producer(buffer1, exchanger);        Consumer consumer = new Consumer(buffer2, exchanger);        Thread threadProducer = new Thread(producer);        Thread threadConsumer = new Thread(consumer);        threadProducer.start();        threadConsumer.start();    }}