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