两个线程之间的同步(生产者与消费者问题)性能优化

计算机中很经典的生产者与消费者的问题,生产者要等到产品消耗完之后才能进行生产,消费者都要等到产品生产完成之后才能消费,也就是说,生产者要等到消费者消费完产品之后才能进行生产,消费者要等到生产者生产完产品之后才能进行消费。
生产者与消费者之间的关系:
生产者>>判断产品是否为空>>空>>生产产品
生产者>>判断产品是否为空>>不空>>不生产产品
消费者>>判断产品是否为空>>空>>不消费产产品
消费者>>判断产品是否为空>>空>>消费产产品
两者之间的逻辑图如下:
两个线程之间的同步(生产者与消费者问题)性能优化_第1张图片
生产者工作完之后,消费者才能工作,消费者工作完之后生产者才能工作,如下图所示:
两个线程之间的同步(生产者与消费者问题)性能优化_第2张图片

下面,使用Java代码来实现生产者与消费者的功能

1、以下代码是实现生产者与消费者的代码普遍实现方法


public class ThreadTest1 {
    // 平果,表示要生产的产品
    static String apple = null;

    // 生产
    static void product() {
        if (apple != null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {

            }
        }
        if (null == apple) {
            System.out.println("product");
            apple = "";
        }
    }

    // 消费
    static void comsume() {
        if (apple == null) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {

            }
        }
        if (null != apple) {
            System.out.println("use");
            apple = null;
        }
    }

    public static void main(String[] args) {
        Thread p = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    product();
                }
            }
        };
        Thread u = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    comsume();
                }
            }
        };
        p.start();
        u.start();
    }
}

运行结果:
两个线程之间的同步(生产者与消费者问题)性能优化_第3张图片
实现原理:
1、生产者生产之前判断产品是否为空,如果不为空(说明消费者还未消费产品),则等待10微秒(给时间消费者进行消费),等待结束后判断产品是否被消费,如果被消费了则生产产品
2、消费者在消费产品之前判断产品是否为空,如果为空(说明生产者还未生产产品),则等待10微秒(给时间生产者进行生产),等待结束后判断产品是否已经生产,如果产品生产了则消费产品
问题:
虽然这样子实现很容易,但是,10微秒的等待时间,如果生产者生产产品的时间远远小于10微秒呢,如果消费者消费产品的时间远远小于20微秒呢?那么CPU就会处于严重浪费的情况。再者,如果生产者和消费者生产与消费所需的时间都大于大于10微秒呢?那么生产者生产的产品总数量就可能会达不到所要的目标,消费者消费的产品总数量也可能不会达到所要的目标。如上图所示的代码,生产者与消费者生产与消费的数量就没有达到目标10了。
或许有人说,如果生产者和消费者都执行一个死循环来判断是否该生产与是否该消费,那么就无需等待10微秒了,也不用害怕10微秒的等待时间不够了。
以下是死循环的代码和结果图:


public class ThreadTest {
    // 平果,表示要生产的产品
    static String apple = null;

    // 生产
    static void product() {
        while (apple != null) {

        }
        System.out.println("product");
        apple = "apple";
    }

    // 消费
    static void comsume() {
        while (apple == null) {

        }
        System.out.println("use");
        apple = null;
    }

    public static void main(String[] args) {
        Thread p = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    product();
                }
            }
        };
        Thread u = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    comsume();
                }
            }
        };
        p.start();
        u.start();
    }
}

两个线程之间的同步(生产者与消费者问题)性能优化_第4张图片
运行结果图显示,利用死循环可以正确实现生产者与消费者功能。
但是,死循环的过程一直在消耗CPU,这样会对CPU产生很大的浪费。

2、优化后的生产者与消费者


public class ThreadTestXH {
    // 平果,表示要生产的产品
    static String apple = null;
    // 生产锁
    static String plock = "productlock";
    // 消费锁
    static String slock = "uselock";

    // 生产
    static void product() {
        if (null != apple) {
            // 生产者进行等待,同时释放CPU资源
            synchronized (plock) {
                try {
                    plock.wait();
                } catch (InterruptedException e) {

                }
            }
        }
        System.out.println("product");
        apple = "apple";
        // 通知消费者进行消费
        synchronized (slock) {
            slock.notify();
        }
    }

    // 消费
    static void comsume() {
        if (null == apple) {
            // 消费者进行等待,同时释放CPU资源
            synchronized (slock) {
                try {
                    slock.wait();
                } catch (InterruptedException e) {

                }
            }
        }
        System.out.println("use");
        apple = null;
        // 通知生产者进行生产
        synchronized (plock) {
            plock.notify();
        }
    }

    public static void main(String[] args) {
        Thread p = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    product();
                }
            }
        };
        Thread u = new Thread() {
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {

                }
                for (int i = 0; i < 10; i++) {
                    comsume();
                }
            }
        };
        p.start();
        u.start();
    }
}

运行结果:
两个线程之间的同步(生产者与消费者问题)性能优化_第5张图片
技术点:
这里使用了同步锁技术与线程技术,wait()方法会当前线程处于等待状态并且释放CPU资源,notify()方法会使等待中的线程重新获得CPU资源并继续执行剩下的代码。
wait()方法和上面代码while(apple==null){}和while(apple!=null){}的死循环实现的效果是一样的,但是区别就是在于,死循环一直占用CPU资源,而wait()方法不占用CPU资源。

你可能感兴趣的:(Java)