Java中Object类的wait()方法和notify()方法来实现生产者---消费者模式

package thread;

import java.util.PriorityQueue;
import java.util.Random;
/**
 * Java在多线程环境下,在那些情况下会释放线程所持锁,那些不会?
 *   一个等待线程只有获取锁时,才会恢复运行。当持有锁的线程不在需要锁时应及时释放该锁这一点很重要避免其他线程过长等待。
 * 释放锁的条件:
 * 1.当执行完同步代码块,就会释放锁。(synchronize)
 * 2.当在同步代码中执行了锁对象的wait()时,当前线程就会释放锁,被放入到锁对象的等待池中。(等待其他线程调用锁对象notify(),从线程池任意提取一线程去竞争锁来恢复执行)
 * 3.当在执行同步代码块过程中,遇到异常而使线程终止,锁被释放。(exception)
 * 不释放锁的条件:
 * 1.在执行同步代码块过程中,调用了Thread的sleep(),当前线程放弃CPU开始睡眠,但是在睡眠过程中并不会释放锁
 * 2.在执行同步代码块过程中,调用了Thread的yield(),当前线程放弃CPU但不会释放锁。
 * 3.在执行同步代码块的过程中,其他线程执行了当前线程对象的suspend()方法,当前线程被暂停,但不会释放锁。
 */
public class ThreadTest7 {
    private int pq_size = 10;
    private PriorityQueue<Integer> pq = new PriorityQueue<Integer>(pq_size);

    public static void main(String[] args) {
        ThreadTest7 test= new ThreadTest7();
        test.new Consumer().start();
        new Thread(test.new Procedure()).start();
    }
    //消费者线程
    public class Consumer extends Thread{
        public void run(){
            while (true) {
                synchronized (pq) {
                    System.out.println("################消费者获取了pq对象的锁################");
                    while(pq.size()==0){//如果队列为空,消费线程需要释放pq对象的锁,被放入到pq对象的等待池中等待pq对象调用notify方法
                        try {
                            System.out.println("队列已空,请生产者进行操作......");
                            Thread.sleep(6000);
                            pq.wait();//线程被挂起,释放线程持有的锁
                            System.out.println("************其他线程调用了bq对象的notify()方法,使线程["+Thread.currentThread().getName()+"]获得bq对象的锁,重新开始从这里执行************");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            pq.notify();
                        }
                    }
                    pq.poll();//从队列中取出一个元素
                    System.out.println("Consumer----------->从队列中取出一个元素,队列现有元素["+pq.size()+"]个");
                    try {
                        Thread.sleep(6000);//
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        pq.notify();
                    }finally{
                        pq.notify();
                    }
                    System.out.println("同步代码块执行完毕,["+Thread.currentThread().getName()+"]线程释放bq对象的锁");
                }
            }
        }
    }
    //生产者线程
    public class Procedure implements Runnable{
        @Override
        public void run() {
            while (true) {
                synchronized (pq) {
                    System.out.println("################生产者获取了pq对象的锁################");
                    while (pq.size()==10) {//队列已满,生产者线程需要释放pq对象的锁,被放入到pq对象的等待池中。同时要从pq对象的等待池中释放一个消费者线程去竞争pq对象的锁
                        try {
                            System.out.println("队列已空,请消费者进行操作......");
                            Thread.sleep(6000);
                            pq.wait();
                            System.out.println("************其他线程调用了bq对象的notify()方法,使线程["+Thread.currentThread().getName()+"]获得bq对象的锁,重新开始从这里执行************");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            pq.notify();
                        }
                    }
                    pq.offer(new Random().nextInt(100));//向队列中添加一个元素
                    System.out.println("Procedure----------->向队列中添加一个元素,队列中现有元素["+pq.size()+"]个");
                    try {
                        Thread.sleep(6000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally{
                        pq.notify();
                    }
                    System.out.println("同步代码块执行完毕,["+Thread.currentThread().getName()+"]线程释放bq对象的锁");
                }
            }
        }
    }

}

猜你喜欢

转载自1749599512.iteye.com/blog/2339975