zoukankan      html  css  js  c++  java
  • 线程的基本协作和生产者消费者

    协作基础(wait/notify)

    Java的根父类是Object,Java在Object类而非Thread类中,定义了一些线程协作的基本方法,使得每个对象都可以调用这些方法,这些方法有两类,一类是wait,另一类是notify。

    wait方法主要有两个:

    public final void wait() throws InterruptedException
    public final native void wait(long timeout) throws InterruptedException;

    一个带时间参数,单位是毫秒,表示最多等待这么长时间,参数为0表示无限期等待。一个不带时间参数,表示无限期等待,实际就是调用wait(0)。在等待期间都可以被中断,如果被中断,会抛出InterruptedException。

    wait实际上做了什么呢?每个对象都有一把锁和一个锁等待队列,一个线程在进入synchronized代码块时,会尝试获取锁,获取不到的话会把当前线程加入等待队列中。其实,除了用于锁的等待队列,每个对象还有另一个等待队列,表示条件队列,该队列用于线程间的协作。调用wait就会把当前线程放到条件队列上并阻塞,表示当前线程执行不下去了,它需要等待一个条件,这个条件它自己改变不了,需要其他线程改变。当其他线程改变了条件后,应该调用Object的notify方法:

    public final native void notify();
    public final native void notifyAll();

    notify做的事情就是从条件队列中选一个线程,将其从队列中移除并唤醒,notifyAll和notify的区别是,它会移除条件队列中所有的线程并全部唤醒。

    wait/notify方法只能在synchronized代码块内被调用,如果调用wait/notify方法时,当前线程没有持有对象锁,会抛出异常java.lang.IllegalMonitorStateException。

    wait的具体过程是:

      1. 把当前线程放入条件等待队列,释放对象锁,阻塞等待,线程状态变为WAITING或TIMED_WAITING
      2. 等待时间到或被其他线程调用notify/notifyAll从条件队列中移除,这时,要重新竞争对象锁
        • 如果能够获得锁,线程状态变为RUNNABLE,并从wait调用中返回
        • 否则,该线程加入对象锁等待队列,线程状态变为BLOCKED,只有在获得锁后才会从wait调用中返回

    线程从wait调用中返回后,不代表其等待的条件就一定成立了,它需要重新检查其等待的条件,一般的调用模式是:

    synchronized (obj) {
        while (条件不成立)
            obj.wait();
        ... // 条件满足后的操作
    }

    生产者/消费者模式

    下面来看一个生产者和消费者的例子:

    /**
     * @author 沉默哥
     * 
     */
    public class MyProducerConsumerDemo {
      static class GoodsQueue {
        private int size;
        private Queue<String> que = new ArrayDeque<String>();
    
        public GoodsQueue(int size) {// 维护一个有界队列,传入队列的最大容量
          super();
          this.size = size;
        }
    
        public synchronized void put(String e) throws InterruptedException {
          while (que.size() == size) {
            System.out.println("队列已满,生产者等待");
            wait();
          }
          que.add(e);
          System.out.println("生产者生产:" + e);
          notify();
        }
    
        public synchronized String take() throws InterruptedException {
          while (que.size() == 0) {
            System.out.println("队列为空,消费者等待");
            wait();
          }
          String e = que.poll();
          System.out.println("消费者消费" + e);
          notify();
          return e;
        }
      }
    
      static class Producer extends Thread {
        GoodsQueue que;
        Random rad = new Random();
    
        public Producer(GoodsQueue que) {
          super();
          this.que = que;
        }
    
        @Override
        public void run() {
          int i = 0;
          try {
            while (true) {
              String e = String.valueOf(i);
              que.put(e);
              i++;
              Thread.sleep(rad.nextInt(1000));// 生产者休息准备下一次生产
            }
          } catch (InterruptedException e1) {
          }
        }
      }
    
      static class Consumer extends Thread {
        GoodsQueue que;
        Random rad = new Random();
    
        public Consumer(GoodsQueue que) {
          super();
          this.que = que;
        }
    
        @Override
        public void run() {
          try {
            while (true) {
              que.take();
              Thread.sleep(rad.nextInt(1000));// 消费者休息准备下一次消费
            }
          } catch (InterruptedException e) {
          }
        }
      }
    
      public static void main(String[] args) throws InterruptedException {
        GoodsQueue que = new GoodsQueue(1);
        Producer pro = new Producer(que);
        Consumer con = new Consumer(que);
        con.start();
        Thread.sleep(500);
        pro.start();
      }
    }

     

  • 相关阅读:
    从 React Router 谈谈路由的那些事
    js中var、let、const区别
    关于Redux到底是个什么鬼
    git 中遇到的问题
    Delphi中BCD和Currency类型
    Mscomm控件安装问题 License information for TMSComm not found.
    以前的某个程序已在安装计算机上创建挂起的文件操作,运行安装程序之前必须重新启动计算机
    win7系统安装SQLServer2000的详细步骤(图文)
    Delphi判断字符串中是否包含汉字,并返回汉字位置
    Sql Server中判断表、列不存在则创建的方法[转]
  • 原文地址:https://www.cnblogs.com/JackPn/p/9426366.html
Copyright © 2011-2022 走看看