生产者和消费者问题(synchronized、Lock)
1.synchronized的生产者和消费者
synchronized是锁住对象 this.wait()释放了锁 并等待 this.notify()随机通知并唤醒同一个对象中的一个线程 this.notifyAll()通知并唤醒同一个对象中的所有线程 注(遇到的问题):若生产消费者模型中生产者和消费者都只有一个线程的话只用this.notify()就可以了 若有多个线程必须用this.notifyAll() 因为this.notify()只通知唤醒一个线程 若只有一个生产者线程在跑 通知唤醒到了另一个生产者线程 导致所有线程等待 造成死锁 休眠判断用while不能用if 因为notify可能假唤醒通知 用while保证wait休眠条件
public class Juc3 { public static void main(String[] args){ Data data = new Data(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.increment(); }catch (Exception e){ e.printStackTrace(); } } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.decrement(); }catch (Exception e){ e.printStackTrace(); } } },"B").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.increment(); }catch (Exception e){ e.printStackTrace(); } } },"C").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.decrement(); }catch (Exception e){ e.printStackTrace(); } } },"D").start(); } } //类中的两个方法synchronized锁 如果new一个对象 这个对象的两个方法锁是同一个锁!!! //同一个对象中如increment方法this.notify();通知锁取消等待就是通知了decrement方法 class Data{ private int number=0; //+1 必须有synchronized //等待必须用while 不用if 防止虚假唤醒 //生产消费者业务代码流程其实就是1.等待2.通知 public synchronized void increment() throws InterruptedException { while (number!=0){ this.wait(); } number++; System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其它线程我执行完了+1 this.notifyAll(); } //-1 public synchronized void decrement() throws InterruptedException { while (number==0){ this.wait(); } number--; System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其它线程我执行完了-1 this.notifyAll(); } }
2.Lock的生产者和消费者
synchronized Lock lock = new ReentrantLock(); lock加锁lock.lock(); lock解锁lock.unlock(); 解锁步骤必须放在try的finally中以防异常 Condition condition = lock.newCondition(); condition对象作线程等待condition.await() 线程唤醒condition.signalAll()
//Lock的生产者和消费者 class LockTest{ public static void main(String[] args) { LockData data = new LockData(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.increment(); }catch (Exception e){ e.printStackTrace(); } } },"A").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.decrement(); }catch (Exception e){ e.printStackTrace(); } } },"B").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.increment(); }catch (Exception e){ e.printStackTrace(); } } },"C").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.decrement(); }catch (Exception e){ e.printStackTrace(); } } },"D").start(); } } class LockData{ private int number=0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //+1 public void increment() { lock.lock(); try { while (number!=0){ condition.await(); } number++; System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其它线程我执行完了+1 condition.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } //-1 public void decrement() { lock.lock(); try { while (number==0){ condition.await(); } number--; System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其它线程我执行完了-1 condition.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }
3.指定唤醒某个方法的线程
上述2个例子是以不同形式实现的同样的代码 因此发现一个问题 唤醒的是同一个对象中的随机的方法或者所有方法 没有指定特定的方法 如A()中唤醒B()唤醒C()唤醒A()循环的话 Condition condition = lock.newCondition(); Condition condition1 = lock.newCondition(); 可以新增多个condition对象 condition1.await()或condition1.signal()让特定的condition对象休眠/唤醒
class LockTest1{ public static void main(String[] args) { LockData1 data = new LockData1(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.A(); }catch (Exception e){ e.printStackTrace(); } } }).start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.B(); }catch (Exception e){ e.printStackTrace(); } } }).start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { data.C(); }catch (Exception e){ e.printStackTrace(); } } }).start(); } } class LockData1{ private int num=1; Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); //A 1 public void A() { lock.lock(); try { while (num!=1){ condition1.await(); } System.out.println(Thread.currentThread().getName()+"=>"+num); num=2; condition2.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } //B 2 public void B() { lock.lock(); try { while (num!=2){ condition2.await(); } System.out.println(Thread.currentThread().getName()+"=>"+num); num=3; condition3.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } //C 3 public void C() { lock.lock(); try { while (num!=3){ condition3.await(); } System.out.println(Thread.currentThread().getName()+"=>"+num); num=1; condition1.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }