美文网首页
Lock实现生产者消费者问题,Condition精准唤醒

Lock实现生产者消费者问题,Condition精准唤醒

作者: CryFace | 来源:发表于2020-04-23 15:31 被阅读0次

之前写了synchronized实现生产者消费者问题,这次用的是lock实现。还有一个就是condition,什么是condition呢?
官方文档是这么说的

  • Condition因素出Object监视器方法( waitnotifynotifyAll )成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock实现。 Lock替换synchronized方法和语句的使用, Condition取代了对象监视器方法的使用。

简单点,就是替代对象监视器了。它的两个常用方法分别是await()signal(),相当于之前的wait()notify()。我们具体来看代码实现

package JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockPC {


    public static void main(String[] args) {

        Resource resource = new Resource();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decrease();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }


    //资源类
    static class Resource {

        //定义一个可重入锁
        Lock lock = new ReentrantLock();

        Condition condition = lock.newCondition();
        
        //生产资源,生产者对其加1,消费者对其减1
        private int num = 0;

        public void incresement() throws InterruptedException {

            lock.lock();

            try {
                //对增加进行判断
                while (num > 0) {
                    condition.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                condition.signalAll();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void decrease() throws InterruptedException {

            lock.lock();

            try {
                //对减少进行判断
                while (num == 0) {
                    condition.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                condition.signalAll();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }
    }

}


打印输出,和我们用synchronized实现一样,有规律的生产和消费。

A->1
B->0
A->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
D->0
C->1
D->0
A->1
......

可是我们发现虽然他们是有规律的生产和消费,但是并没有按照我们的线程的顺序来打印。唤醒的时候消费和生产都在竞争。那么我们如何让线程按照我们指定的顺序来达到精准唤醒呢?
我们可以多定义几个condition,然后在执行完唤醒指定的condition!

package JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockPC {


    public static void main(String[] args) {

        Resource resource = new Resource();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresementA();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decreaseB();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresementC();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decreaseD();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }


    //资源类
    static class Resource {

        //定义一个可重入锁
        Lock lock = new ReentrantLock();

        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();
        Condition conditionD = lock.newCondition();

        //生产资源,生产者对其加1,消费者对其减1
        private int num = 0;

        public void incresementA() throws InterruptedException {

            lock.lock();
            try {
                //对增加进行判断
                while (num > 0) {
                    conditionA.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionB.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void decreaseB() throws InterruptedException {

            lock.lock();
            try {
                //对减少进行判断
                while (num == 0) {
                    conditionB.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionC.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            };
        }

        public void incresementC() throws InterruptedException {

            lock.lock();
            try {
                //对增加进行判断
                while (num > 0) {
                    conditionC.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionD.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void decreaseD() throws InterruptedException {

            lock.lock();
            try {
                //对减少进行判断
                while (num == 0) {
                    conditionD.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionA.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            };
        }
    }

}


A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0

Condition实现可以提供Object监视器方法的行为和语义,例如有保证的通知顺序,或者在执行通知时不需要锁定。 如果一个实现提供了这样的专门的语义,那么实现必须记录这些语义。
需要注意的是,condition也是会发生虚假唤醒的,所以我们需要把判断写进循环语句里。

相关文章

网友评论

      本文标题:Lock实现生产者消费者问题,Condition精准唤醒

      本文链接:https://www.haomeiwen.com/subject/kqkaihtx.html