java實現<生產者-消費者>的兩種方式
阿新 • • 發佈:2021-01-28
技術標籤:Java
1,兩種方式簡單介紹:
1.1 使用Synchronized關鍵字
Synchronized + wait() + notifyAll()
注意點:
判斷條件用while迴圈,如果用if會出現虛假喚醒。
1.2使用Lock介面
ReentrantLock + Condition + await() + singsignalAll()
注意點:
Lock lock = new ReentrantLock(); //注意Lock 的實現類
Condition condition = lock.newCondition(); //注意Condition通過lock獲取
2,使用synchronized
直接上程式碼:
/**
* 資源類
* @author dangkaimin
*/
public class Source {
private int number = 0; //資源
/* 生產 */
public synchronized void push() {
while(number == 1){ //判斷 注意判斷條件用while,如果用if會出現虛假喚醒
this.wait(); //等待
}
number = 1; //業務
System. out.println(Thread.currentThread().getName() + "push number = " + number);
this.notifyAll(); //通知
}
/* 消費 */
public synchronized void pop() {
while(number == 0){ //判斷
this.wait(); //等待
}
number = 0; //業務
System.out.println (Thread.currentThread().getName() + "pop number = " + number);
this.notifyAll(); //通知
}
public static void main(String[] args){
Source source = new Source();
/* 生產者*/
new Thread( () -> {
while(true) {
source.push();
}
}).start();
/* 消費者*/
new Thread( () -> {
while(true) {
source.pop();
}
}).start();
}
3,使用Lock介面
/**
* 資源類
* @author dangkaimin
*/
public class Source {
private int number = 0; //資源
private Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
/* 生產 */
public void push() {
lock.lock();
try {
while(number == 1){ //判斷
condition.await(); //等待
}
number = 1; //業務
System.out.println(Thread.currentThread().getName() + " push number = " + number);
condition.signalAll(); //通知
}finally {
lock.unlock();
}
}
/* 消費 */
public void pop() {
lock.lock();
try {
while(number == 0){ //判斷
condition.await(); //等待
}
number = 0; //業務
System.out.println(Thread.currentThread().getName() + " pop number = " + number);
condition.signalAll(); //通知
} finally {
lock.unlock();
}
}
public static void main(String[] args){
Source source = new Source();
/* 生產者*/
new Thread( () -> {
while(true) {
source.push();
}
},"A").start();
/* 消費者*/
new Thread( () -> {
while(true) {
source.pop();
}
},"B").start();
}
}
3,Lock升級版:通過condition實現執行緒的精準通知。
流程:A喚醒B,B喚醒C,C喚醒A
注意點:
- 使用一個鎖的不同condition
- 注意判斷條件的合理。
/**
* 資源類
* @author dangkaimin
*/
public class Source {
private int number = 1; //資源
private Lock lock = new ReentrantLock();
Condition condition_A = lock.newCondition();
Condition condition_B = lock.newCondition();
Condition condition_C = lock.newCondition();
public void method_A() {
lock.lock();
try {
while(number != 1){ //判斷
condition_A.await(); //等待
}
number = 2;
System.out.println(Thread.currentThread().getName() + " A number = " + number);
condition_B.signal(); //喚醒A
}catch(Exception e){
}finally {
lock.unlock();
}
}
/* 消費 */
public void method_B() {
lock.lock();
try {
while(number != 2){ //判斷
condition_B.await(); //等待
}
number = 3;
System.out.println(Thread.currentThread().getName() + " B number = " + number);
condition_C.signal(); //喚醒B
}catch(Exception e){
} finally {
lock.unlock();
}
}
public void method_C() {
lock.lock();
try {
while(number != 3){ //判斷
condition_C.await(); //等待
}
number = 1;
System.out.println(Thread.currentThread().getName() + " C number = " + number);
condition_A.signal(); //喚醒A
}catch(Exception e){
} finally {
lock.unlock();
}
}
public static void main(String[] args){
Source source = new Source();
new Thread( () -> {
while(true) {
source.method_A();
}
},"method_A").start();
new Thread( () -> {
while(true) {
source.method_B();
}
},"method_B").start();
new Thread( () -> {
while(true) {
source.method_C();
}
},"method_C").start();
}
}
精準通知結果如下:
method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
...