前言:打算回顾一下以前学过的知识点,先以一个小程序开始吧
下面的代码是中午刚写的,传统的synchronized、while、wait、notifyAll的示例就不写了
1 package com.meshuce.concurrencyTest; 2 3 import java.util.LinkedList; 4 import java.util.concurrent.TimeUnit; 5 import java.util.concurrent.locks.Condition; 6 import java.util.concurrent.locks.ReentrantLock; 7 8 public class Test1 { 9 10 private static final int MAX_SIZE = 100; 11 12 private static LinkedList<Object> list = new LinkedList<Object>(); // 容器 13 14 private static ReentrantLock lock = new ReentrantLock(); 15 16 private static Condition producer = lock.newCondition(); 17 18 private static Condition comsumer = lock.newCondition(); 19 20 public static void main(String[] args) { 21 22 for (int i = 0; i < 10; i++) { // 10个消费者 23 new Thread(()-> { 24 25 for (int j = 0; j < 10; j++) { // 每个消费者消费10个产品 26 try { 27 lock.lock(); 28 while(list.size() == 0) { 29 System.out.println(Thread.currentThread().getName()+":当前有"+list.size()+"个产品,缓冲区已空,请等待生产者生产"); 30 try { 31 comsumer.await(); // 消费者等待 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 } 36 37 list.removeFirst(); 38 System.out.println(Thread.currentThread().getName()+":消费了一个产品,当前产品个数为 " + list.size()); 39 // 如果想看得清晰点,可以释放下面的代码段 40 // try { 41 // TimeUnit.MILLISECONDS.sleep(400); 42 // } catch (InterruptedException e) { 43 // e.printStackTrace(); 44 // } 45 producer.signalAll(); // 唤醒所有生产者 46 } finally { 47 lock.unlock(); 48 } 49 } 50 }, "comsumer"+i).start(); 51 } 52 53 // try { 54 // TimeUnit.MILLISECONDS.sleep(2000); // 等个2秒钟,让消费者都启动 55 // } catch (InterruptedException e) { 56 // e.printStackTrace(); 57 // } 58 59 for (int i = 0; i < 2; i++) { // 2个生产者 60 new Thread(()-> { 61 62 for (int j = 0; j < 50; j++) { // 每个生产者生产50个产品 63 try { 64 lock.lock(); // 先拿锁 65 while(list.size() == MAX_SIZE) { 66 System.out.println(Thread.currentThread().getName()+":当前有"+list.size()+"个产品,缓冲区已满,请等待消费者消费"); 67 try { 68 producer.await(); // 生产者等待 69 } catch (InterruptedException e) { 70 e.printStackTrace(); 71 } 72 } 73 74 list.add(new Object()); 75 System.out.println(Thread.currentThread().getName()+": 生产了一个产品,当前产品个数为 " + list.size()); 76 77 // 如果想看得清晰点,可以释放下面的代码段 78 // try { 79 // TimeUnit.MILLISECONDS.sleep(200); 80 // } catch (InterruptedException e) { 81 // e.printStackTrace(); 82 // } 83 comsumer.signalAll(); // 唤醒所有消费者 84 } finally { 85 lock.unlock(); 86 } 87 } 88 }, "producer"+i) .start(); 89 } 90 } 91 92 93 }
简单提一下:
1、使用手动锁需要加 finally 进行显示地释放,否则很容易造成死锁
2、另外,yield 和 notify 的区别:在唤醒其它线程的时候,yield不会释放锁,notify会释放