W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
一、信號燈法 1.不使用信號燈法,僅使用synchronize解決生產(chǎn)者消費者問題的錯誤范例:
/**
* 如果不使用信號燈法,可能出現(xiàn)以下幾種情況:
* 1.消費者可能在電影還沒有賦值就開始觀看,看到了null。
* 2.消費者可能看了一遍電影之后又看了同一部電影,甚至連續(xù)好多次。
* 3.生產(chǎn)者可能在沒有人觀看這部電影時就更換的電影,即重新賦值。
* 總結(jié):因為synchronize只是增加了一個限制,即只能有一個線程訪問,并不具有其他邏輯,
* 也就是說不會去判斷資源的多少、資源會不會總被一個線程使用,若要實現(xiàn)其他邏輯,就需要其他代碼輔助。
*/
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 + "》電影。");
}
}
/**
*生產(chǎn)者:播放者。
*/
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解決生產(chǎn)者消費者問題的正確范例:
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 生產(chǎn)者生產(chǎn),消費者等待,生產(chǎn)完成后通知消費。
//flag -->F 消費者消費,生產(chǎn)者等待,消費完成后通知生產(chǎn)。
//wait()等待,釋放鎖,sleep不釋放鎖。
//notify() 喚醒在此鎖等待隊列的最前面的一個線程取得鎖。
//notifyAll() 喚醒在此鎖等待隊列的所有線程爭奪鎖。
private boolean flag = true;
public synchronized void play(String name) {//播放
if(!flag) {//生產(chǎn)者等待
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//開始生產(chǎn)
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name;
System.out.println("我要播放一部《" + name + "》電影。");
//生產(chǎn)完畢
//更改信號燈
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;
//通知生產(chǎn)
this.notifyAll();
}
}
/**
*生產(chǎn)者:播放者。
*/
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();
}
}
}
運行結(jié)果:
我要播放一部《左青龍》電影。
我看了一部《左青龍》電影。
我要播放一部《右白虎》電影。
我看了一部《右白虎》電影。
我要播放一部《左青龍》電影。
我看了一部《左青龍》電影。
我要播放一部《右白虎》電影。
我看了一部《右白虎》電影。
......
二、管盛法 暫不研究。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: