生产者消费者
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();
}
}
}
运行结果:
我要播放一部《左青龙》电影。
我看了一部《左青龙》电影。
我要播放一部《右白虎》电影。
我看了一部《右白虎》电影。
我要播放一部《左青龙》电影。
我看了一部《左青龙》电影。
我要播放一部《右白虎》电影。
我看了一部《右白虎》电影。
......
二、管盛法 暂不研究。
以上内容是否对您有帮助:
← 死锁
更多建议: