多线程实战二

问题

  写一个固定容量同步容器,拥有put和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用。

解法一

  这是一个典型的生产者消费者问题,可以通过wait()和notifyAll()方法来实现。

public class MyContainer4 {
    private LinkedList<String> list = new LinkedList<>();
    private static final int MAX_SIZE = 10;

    public synchronized int getCount() {
        return list.size();
    }

    public synchronized void put(String s) {
        while (getCount() >= MAX_SIZE) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " put " + s);
        list.add(s);
        this.notifyAll();
    }

    public synchronized String get() {
        while (getCount() == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        String s = list.removeFirst();
        this.notifyAll();
        return s;
    }

    public static void main(String[] args) {
        MyContainer4 myContainer4 = new MyContainer4();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String s = myContainer4.get();
                    System.out.println(Thread.currentThread().getName() + " get: " + s);
                }
            }, "consumer" + i).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    myContainer4.put(Thread.currentThread().getName() + "product");
                }
            }, "producer" + i).start();
        }
    }
}

解法二

  上面的解法有一个弊端,当消费者从list中获取数据之后,会调用notifyAll()方法来唤醒所有的线程。其实消费者取完数据之后,只需要唤醒生产者线程即可,没必要唤醒其他的消费者。为了更加精确地唤醒生产者或消费者,可以使用ReentrantLock来实现。

public class MyContainer5 {
    private LinkedList<String> list = new LinkedList<>();
    private static final int MAX_SIZE = 10;

    Lock lock = new ReentrantLock();
    Condition productorCondition = lock.newCondition();
    Condition consumerCondition = lock.newCondition();

    public void put(String s) {
        try {
            lock.lock();
            while (list.size() >= MAX_SIZE) {
                productorCondition.await(); // 进入生产者等待队列
            }
            System.out.println(Thread.currentThread().getName() + " put " + s);
            list.add(s);
            consumerCondition.signalAll(); // 生产一个元素后,唤醒消费者等待队列中的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public String get() {
        String s = null;
        try {
            lock.lock();
            while (list.size() == 0) {
                consumerCondition.await(); // 进入消费者等待队列
            }
            s = list.removeFirst();
            productorCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return s;
    }

    public static void main(String[] args) {
        MyContainer5 myContainer4 = new MyContainer5();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String s = myContainer4.get();
                    System.out.println(Thread.currentThread().getName() + " get: " + s);
                }
            }, "consumer" + i).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    myContainer4.put(Thread.currentThread().getName() + "product");
                }
            }, "producer" + i).start();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值