首页 > 编程语言 > 详细

JAVA学习(等待唤醒常考例子:生产者消费者,Lock接口,Condition接口)

时间:2021-04-01 23:20:54      阅读:24      评论:0      收藏:0      [点我收藏+]

一、多生产者多消费者

1.使用while判断标记,解决了线程获取执行权限后,是否要运行的问题。

  因为使用if判断时,当线程被唤醒后因为已经判断过标记,线程就会继续执行,倘若此时已有生产的产品未被消费,线程仍然会生产产品。

2.notifyAll解决了,本方线程一定会唤醒对象线程。

  仅使用notify唤醒单线程的时候,有可能会唤醒本方线程,因为此时的标记还未改变,而对方的线程仍在冻结,在进行判断的时候本方的线程 会因为标记的判断成功而陷入冻结,导致没有线程处于唤醒状态。进而导致死锁。

public class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;
    public synchronized void set(String name){   //生产操作
        while(flag)
            try{this.wait();}catch(InterruptedException e){}
        this.name = name + count;
        count++;
        System.out.println(Thread.currentThread().getName()+"生产了。。。"+this.name);
        flag = true;
        this.notifyAll();
    }
    public synchronized void out(){         //消费操作
        while(!flag)
            try{this.wait();}catch(InterruptedException e){}
        System.out.println(Thread.currentThread().getName()+"消费了。。。"+this.name);
        flag = false;
        this.notifyAll();
    }

}

public class Produce implements Runnable{
    private Resource r;
    Produce(Resource r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.set("烤鸭");   //调用生产操作
        }
    }
}

public class Consumer implements Runnable{
    private Resource r;
    Consumer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true) {
            r.out();         //调用消费操作
        }
    }
}

public class ResourceDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Produce in = new Produce(r);
        Consumer out = new Consumer(r);

        Thread t0 = new Thread(in);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        Thread t3 = new Thread(out);
        t0.start();
        t1.start();
        t2.start();
        t3.start();
    }
}

 使用while语句以及notifyAll语句虽然解决了死锁的问题,但是在唤醒全部线程的同时,判断己方的线程会导致资源的浪费,JDK1.5版本以后的Lock接口解决了这个问题。

二、Lock接口

Lock提供了比使用synchronize接口更广泛灵活的操作,被用来替代synchronize。

Condition接口替代了Object监视器方法的使用。

新的接口Condition将Object监视器方法(wait,notify,notifyAll)分解为既然不同的对象

 

之前使用synchronize接口时,因为生产者与消费者之间使用同一把锁来保持同步,所以只有一个监视器,却要同时监视生产者和消费者两者的线程。

使用新的Lock接口时,Condition接口可以将多个监视器与同一把锁进行绑定,

import java.util.concurrent.locks.*;
public class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;
    Lock lock = new ReentrantLock();
    Condition pro_con = lock.newCondition();  //通过已有的锁获取两组锁上的监视器对象,一组监视生产者,一组监视消费者
    Condition con_con = lock.newCondition();
    public void set(String name){    //生产操作
        lock.lock();      //创建一个锁
        try {
            while(flag)   //消费者等待
                try {con_con.await();}catch(InterruptedException e){}
            this.name = name + count;
            count++;
            System.out.println(Thread.currentThread().getName() + "生产了。。。" + this.name);
            flag = true;
            pro_con.signal();  //生产者唤醒
        }
        finally {
            lock.unlock();
        }
    }
    public void out() {       //消费操作
        lock.lock();
        try {
            while(!flag)    //生产者等待
                try {pro_con.await();} catch (InterruptedException e) {}
            System.out.println(Thread.currentThread().getName() + "消费了。。。" + this.name);
            flag = false;
            con_con.signal();   //消费者唤醒
        }
        finally {
            lock.unlock();
        }
    }
}

public class Person {
    private int age;
    Person(int age){
        this.age = age;
    }
    public boolean equals(Object obj){
        Person p = (Person)obj;
        return this.age == p.age;
    }
}

public class Consumer implements Runnable{
    private Resource r;
    Consumer(Resource r){
        this.r = r;
    }
    public void run(){
        while(true) {
            r.out();
        }
    }
}

public class ResourceDemo {
    public static void main(String[] args) {
        Resource r = new Resource();
        Produce in = new Produce(r);
        Consumer out = new Consumer(r);

        Thread t0 = new Thread(in);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        Thread t3 = new Thread(out);
        t0.start();
        t1.start();
        t2.start();
        t3.start();
    }
}

Lock接口的出现替代了同步代码块或者同步函数,将同步的隐式操作变成显示操作,

同时更为灵活,可以一把锁加上多组监视器。

JAVA学习(等待唤醒常考例子:生产者消费者,Lock接口,Condition接口)

原文:https://www.cnblogs.com/gmangofight/p/14607478.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!