生产者消费者

2019-07-07 23:45 更新

一、信号灯法 1.不使用信号灯法,仅使用synchronize解决生产者消费者问题的错误范例:

/**
 * 如果不使用信号灯法,可能出现以下几种情况:
 * 1.消费者可能在电影还没有赋值就开始观看,看到了null。
 * 2.消费者可能看了一遍电影之后又看了同一部电影,甚至连续好多次。
 * 3.生产者可能在没有人观看这部电影时就更换的电影,即重新赋值。
 * 总结:因为synchronize只是增加了一个限制,即只能有一个线程访问,并不具有其他逻辑,
 * 也就是说不会去判断资源的多少、资源会不会总被一个线程使用,若要实现其他逻辑,就需要其他代码辅助。
 */
public class MyThread{
    public static void main(String[] args) throws InterruptedException {
        //共同的资源:
        Movie m = new Movie();

        
        //多线程:
        Player p = new Player(m);
        Watcher w = new Watcher(m);

        
        new Thread(p).start();
        new Thread(w).start();
    }
}
/**
 * 一个场景,共同的资源。
 */
class Movie{
    private String name;
    public synchronized void play(String name) {//播放
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        this.name = name;
        System.out.println("我要播放一部《" + name + "》电影。");
    } 
    public synchronized void watch() {//观看
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("我看了一部《" + name + "》电影。");
    }
}
/**
 *生产者:播放者。
 */
class Player implements Runnable{
    private Movie m;
    public Player(Movie m) {
        this.m = m;
    }
    @Override
    public void run() {
        for(int i = 0; i < 20; i++) {
            if(i%2 == 0) {
                m.play("左青龙");
            } else {
                m.play("右白虎");
            }
        }
    }
}
/**
 *消费者:观众。
 */
class Watcher implements Runnable{
    private Movie m;
    public Watcher(Movie m) {
        this.m = m;
    }
    @Override
    public void run() {
        for(int i = 0; i < 20; i++) {
            m.watch();
        }
    }
}

2.使用信号灯法,配合使用synchronize解决生产者消费者问题的正确范例:

public class MyThread{
    public static void main(String[] args) throws InterruptedException {
        //共同的资源:
        Movie m = new Movie();

        
        //多线程:
        Player p = new Player(m);
        Watcher w = new Watcher(m);

        
        new Thread(p).start();
        new Thread(w).start();
    }
}
/**
 * 一个场景,共同的资源。
 */
class Movie{
    private String name;
    //信号灯
    //flag -->T 生产者生产,消费者等待,生产完成后通知消费。
    //flag -->F 消费者消费,生产者等待,消费完成后通知生产。
    //wait()等待,释放锁,sleep不释放锁。
    //notify() 唤醒在此锁等待队列的最前面的一个线程取得锁。
    //notifyAll() 唤醒在此锁等待队列的所有线程争夺锁。
    private boolean flag = true;

    
    public synchronized void play(String name) {//播放
        if(!flag) {//生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //开始生产
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        this.name = name;
        System.out.println("我要播放一部《" + name + "》电影。");
        //生产完毕
        //更改信号灯
        this.flag = false;
        //通知消费
        this.notify();
    } 
    public synchronized void watch() {//观看
        if(flag) {//消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //开始消费
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("我看了一部《" + name + "》电影。");
        //消费完毕
        //更改信号灯,消费停止
        this.flag = true;
        //通知生产
        this.notifyAll();
    }
}
/**
 *生产者:播放者。
 */
class Player implements Runnable{
    private Movie m;
    public Player(Movie m) {
        this.m = m;
    }
    @Override
    public void run() {
        for(int i = 0; i < 20; i++) {
            if(i%2 == 0) {
                m.play("左青龙");
            } else {
                m.play("右白虎");
            }
        }
    }
}
/**
 *消费者:观众。
 */
class Watcher implements Runnable{
    private Movie m;
    public Watcher(Movie m) {
        this.m = m;
    }
    @Override
    public void run() {
        for(int i = 0; i < 20; i++) {
            m.watch();
        }
    }
}

运行结果:

我要播放一部《左青龙》电影。
我看了一部《左青龙》电影。
我要播放一部《右白虎》电影。
我看了一部《右白虎》电影。
我要播放一部《左青龙》电影。
我看了一部《左青龙》电影。
我要播放一部《右白虎》电影。
我看了一部《右白虎》电影。
......

二、管盛法 暂不研究。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号