java实现双缓冲生产者消费者模型的两种方式

方式一:借助wait() notify()实现生产者攒够N个队列,消费者再消费

优点:对于擅长 块处理 的消费者线程来说,明显提高性能,而且消费者wait,可以把CPU空置给生产者。

相比于下面方式二,不会导致CPU的空转,和消费者线程的浪费。

提出方式一的问题背景是生产者负责实时接收消息,攒够1000个后,通知消费者线程调用neo4j接口,插入图数据库。

package test;

import java.util.ArrayList;

public class Test2 {

    static ArrayList a = new ArrayList();
    static ArrayList b = new ArrayList();
    static ArrayList provider;
    static ArrayList consumer;
    public int flag=0;

    public static void main(String[] args) throws InterruptedException {
        provider = a;
        consumer = b;
        Test2 test2 = new Test2();
        Producer2 p = new Producer2(test2);
        Consumer2 c = new Consumer2(test2);
        Thread t1 = new Thread(p);
        t1.start();
        Thread t2 = new Thread(c);
        t2.start();
        t1.join();
        System.out.println("aa");
        t2.join();
        System.out.println("a");
        for (int i = 0; i < a.size(); i++) {
            System.out.println(a.get(i));
        }

        System.out.println("b");
        for (int i = 0; i < b.size(); i++) {
            System.out.println(b.get(i));
        }
    }

    synchronized ArrayList get() throws InterruptedException {
        ArrayList tmp;
        if (provider.size() <= 10)
            wait(200);
        tmp = provider;
        provider = consumer;
        consumer = tmp;
        flag=(flag+1)%2;
        System.out.println("queue "+flag+" has "+consumer.size()+" wait");
        return consumer;
    }

    synchronized void set(int i) {

        provider.add(i);

        System.out.println(flag+":生产了:" + i);
        if (provider.size() > 10)
            notify();

    }
}

class Producer2 implements Runnable {
    private Test2 bank;

    public Producer2(Test2 bank) {
        this.bank = bank;
    }

    public void run() {
        for (int i = 0; i < 200; i++) {
            bank.set(i);
            try {
                Thread.sleep((int) (Math.random() * 2));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer2 implements Runnable {
    private Test2 bank;

    public Consumer2(Test2 bank) {
        this.bank = bank;
    }

    public void run() {
        for (int i = 0; i < 50; i++) {
            ArrayList queue;
            try {
                queue = bank.get();
                for (int j = 0; j < queue.size(); j++) {
                    System.out.println("消费了:" + queue.get(j));
                    Thread.sleep((int) (Math.random() * 2));

                }
                queue.clear();
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }
}
 

 

 

方式二:ReenTrantLock实现只要消费队列为空,就抢占式交换队列(此时可能生产者队列为空或者很少)

优点:这种方式消费者实时性高,并且一直不会阻塞。

缺点:如果生产者速度小于消费者,那么会频繁进入临界区进行交换,导致性能消耗。而且如果生产者队列,长时间为空,则消费者线程进入无限空转之中。

package test;

import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    private static ReentrantLock lock = new ReentrantLock();

    static ArrayList a = new ArrayList();
    static ArrayList b = new ArrayList();
    static ArrayList provider;
    static ArrayList consumer;

    public static void main(String[] args) throws InterruptedException {
        provider=a;
        consumer=b;
        Producer p = new Producer();
        Consumer c = new Consumer();
        Thread t1=new Thread(p);
        t1.start();
        Thread t2=new Thread(c);
        t2.start();
        t1.join();
        t2.join();
        System.out.println("a");
        for(int i=0;i         {System.out.println(a.get(i));}

        System.out.println("b");
        for(int i=0;i         {System.out.println(b.get(i));}
    }

    static ArrayList get() {
        ArrayList tmp;
        lock.lock();
        try {
            tmp = provider;
            provider = consumer;
            consumer = tmp;
        } finally {
            lock.unlock();
        }

        return consumer;
    }

    static void set(int i) {
        lock.lock();

        try {
            provider.add(i);
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable {

    public void run() {
        for (int i = 0; i < 200; i++) {
            Test.set(i);
            System.out.println("生产了:" + i);
            try {
                Thread.sleep((int) (Math.random() * 2));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {

    public void run() {
        for (int i = 0; i < 40; i++) {
            ArrayList queue = Test.get();
            System.out.println("consumer");
            for (int j = 0; j < queue.size(); j++) {
                System.out.println("消费了:" + queue.get(j));
                try {
                    Thread.sleep((int) (Math.random() * 2));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.clear();

        }
    }
}
 

你可能感兴趣的:(线程同步)