并发编程(3):生产者与消费者

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

  • 新建:就是刚使用new方法,new出来的线程;

  • 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;

  • 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;

  • 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;

  • 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

完整的生命周期图如下:

 

 

 

Version1:使用wait和notify实现

class Consumer implements Runnable {
    private List<String> queue;

    public Consumer(List<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }

                String current = null;
                synchronized (queue) {
                    if (queue.size() == 0) {
                        queue.wait();

                    }

                    current = queue.remove(0);
                    queue.notifyAll();
                }

                System.out.println(Thread.currentThread().getId() + " 消费了:" + current);
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Producer implements Runnable {
    private List<String> queue;
    private int length;

    public Producer(List<String> queue, int length) {
        this.queue = queue;
        this.length = length;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                Random r = new Random();
                long temp = r.nextInt(100);
                System.out.println(Thread.currentThread().getId() + " 生产了:" + temp);
                String data = String.valueOf(temp);
                synchronized (queue) {
                    if (queue.size() >= length) {

                        queue.wait();
                    }
                    queue.add(data);
                    queue.notifyAll();

                }
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        List<String> queue = new ArrayList<>();

        Producer p1 = new Producer(queue, 10);
        Producer p2 = new Producer(queue, 10);
        Producer p3 = new Producer(queue, 10);
        Consumer c1 = new Consumer(queue);
        Consumer c2 = new Consumer(queue);
        Consumer c3 = new Consumer(queue);

        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(p1);
        service.execute(p2);
        service.execute(p3);
        service.execute(c1);
        service.execute(c2);
        service.execute(c3);
        service.shutdown();
    }
}

 

Version2:使用await和signal实现

class Consumer implements Runnable {
    private List<String> queue;

    public Consumer(List<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                String current = null;
                try {
                    Main.lock.lock();
                    if (queue.size() == 0) {
                        System.out.println("队列空了,赶紧生产吧!==============");
                        Main.empty.await();
                    }
                    current = queue.remove(0);
//                    Main.full.signalAll();
                } finally {
                    Main.lock.unlock();
                }
                System.out.println("线程" + Thread.currentThread().getId() + " 消费了:" + current);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Producer implements Runnable {
    private List<String> queue;
    private int length;

    public Producer(List<String> queue, int length) {
        this.queue = queue;
        this.length = length;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                Random r = new Random();
                long temp = r.nextInt(100);
                System.out.println("线程" + Thread.currentThread().getId() + " 生产了:" + temp);
                String data = String.valueOf(temp);
                try {
                    Main.lock.lock();
                    if (queue.size() >= length) {
                        System.out.println("队列满了,不要生产了!==============");
                        Main.full.await();
                    }
                    queue.add(data);
//                    Main.empty.signalAll();
                } finally {
                    Main.lock.unlock();
                }
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {
    public static Lock lock = new ReentrantLock();
    public static Condition full = lock.newCondition();
    public static Condition empty = lock.newCondition();

    public static void main(String[] args) {
        List<String> queue = new ArrayList<>();
        Producer p1 = new Producer(queue, 10);
        Producer p2 = new Producer(queue, 10);
        Producer p3 = new Producer(queue, 10);
        Consumer c1 = new Consumer(queue);
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(p1);
        service.execute(p2);
        service.execute(p3);
        service.execute(c1);
    }
}

 

Version3:使用BlockingQueue实现

 

public class Consumer implements Runnable {
    private BlockingQueue<String> queue;

    public Consumer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }

                String current = queue.take();

                System.out.println(Thread.currentThread().getId() + " 消费了:" + current);
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Producer implements Runnable {
    private BlockingQueue<String> queue;

    public Producer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                Random r = new Random();
                long temp = r.nextInt(100);
                System.out.println(Thread.currentThread().getId() + " 生产了:" + temp);
                String data = String.valueOf(temp);
                queue.put(data);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

        Producer p1 = new Producer(queue);
        Producer p2 = new Producer(queue);
        Producer p3 = new Producer(queue);
        Consumer c1 = new Consumer(queue);
        Consumer c2 = new Consumer(queue);
        Consumer c3 = new Consumer(queue);

        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(p1);
        service.execute(p2);
        service.execute(p3);
        service.execute(c1);
        service.execute(c2);
        service.execute(c3);
        service.shutdown();
    }

}

 

1、缓冲池的数量的Size是用来限定生产者的,达到上限不能生产;消费者只负责从缓冲池取数据,当缓冲池为0时,无法消费;

2、生产者和消费者就是Runnable;

3、wait和notify需要和sync关键字一起使用,尽量不要在sync中使用sleep;

4、notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁;

5、wait是需要notify或notifyAll唤醒的,只不过是线程结束时,虚拟机帮我们做了一次notifyAll(调用链是:run() -> thread_main_inner() -> exit() -> ensure_join()。意思就是线程要结束之前肯定会调上边这个ensure_join方法,而这个方法执行了lock.notify_all(thread));

 6、notify和notifyAll的区别:notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁;

 
posted @ 2020-06-10 17:16  北大教授  阅读(142)  评论(0)    收藏  举报