题目(生产者消费者模式):自定义同步容器,容器容量上限为10。可以在多线程中应用,并保证数据线程安全。
方式一:synchronized
/** * 生产者消费者 * wait¬ify * wait/notify都是和while配合应用的。可以避免多线程并发判断逻辑失效问题。 */ import java.util.LinkedList; import java.util.concurrent.TimeUnit; public class TestContainer01<E> { private final LinkedList<E> list = new LinkedList<>(); private final int MAX = 10; private int count = 0; public static void main(String[] args) { final TestContainer01<String> c = new TestContainer01<>(); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 5; j++) { System.out.println(c.get()); } } }, "consumer" + i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 25; j++) { c.put("container value " + j); } } }, "producer" + i).start(); } } public synchronized int getCount() { return count; } public synchronized void put(E e) { while (list.size() == MAX) { try { this.wait(); } catch (InterruptedException e1) { e1.printStackTrace(); } } list.add(e); count++; this.notifyAll(); } public synchronized E get() { E e = null; while (list.size() == 0) { try { this.wait(); } catch (InterruptedException e1) { e1.printStackTrace(); } } e = list.removeFirst(); count--; this.notifyAll(); return e; } }
方法二:ReentrantLock
/** * 生产者消费者 * 重入锁&条件 * 条件 - Condition, 为Lock增加条件。当条件满足时,做什么事情,如加锁或解锁。如等待或唤醒 */ import java.util.LinkedList; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestContainer02<E> { private final LinkedList<E> list = new LinkedList<>(); private final int MAX = 10; private int count = 0; private Lock lock = new ReentrantLock(); private Condition producer = lock.newCondition(); private Condition consumer = lock.newCondition(); public static void main(String[] args) { final TestContainer02<String> c = new TestContainer02<>(); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 5; j++) { System.out.println(c.get()); } } }, "consumer" + i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e1) { e1.printStackTrace(); } for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 25; j++) { c.put("container value " + j); } } }, "producer" + i).start(); } } public int getCount() { return count; } public void put(E e) { lock.lock(); try { while (list.size() == MAX) { System.out.println(Thread.currentThread().getName() + " 等待。。。"); // 进入等待队列。释放锁标记。 // 借助条件,进入的等待队列。 producer.await(); } System.out.println(Thread.currentThread().getName() + " put 。。。"); list.add(e); count++; // 借助条件,唤醒所有的消费者。 consumer.signalAll(); } catch (InterruptedException e1) { e1.printStackTrace(); } finally { lock.unlock(); } } public E get() { E e = null; lock.lock(); try { while (list.size() == 0) { System.out.println(Thread.currentThread().getName() + " 等待。。。"); // 借助条件,消费者进入等待队列 consumer.await(); } System.out.println(Thread.currentThread().getName() + " get 。。。"); e = list.removeFirst(); count--; // 借助条件,唤醒所有的生产者 producer.signalAll(); } catch (InterruptedException e1) { e1.printStackTrace(); } finally { lock.unlock(); } return e; } }
区别:synchronized的notify会唤醒所有的线程(生产者+消费者),而ReentrantLock的Condition会精准的唤醒生产者或者消费者。但是两者效率差别不大。
Stay hungry,stay foolish !