1. 程式人生 > 其它 >6.21Java多執行緒併發管程法

6.21Java多執行緒併發管程法

6.21Java多執行緒併發管程法

核心:

緩衝區

模型分析

  • 生產者--->多執行緒(有多個操作)

  • 消費者--->多執行緒

  • 緩衝區--->併發容器(JUC包下已經提供了)--->操作商品

功能

  • 緩衝區需要實現什麼功能

  • 需要併發什麼操作

    • 併發存--->什麼時候可以存(容器不夠時,需要等待)

    • 併發取--->什麼時候可以取(裡面有資料,就可以取。空容器,進行等待。等待生產)

wait同樣是阻塞的一種,但是會釋放鎖。

當notify或者notifyAll被呼叫的時候執行緒就進入了可執行狀態

有資源的鎖定和陣列越界問題
package iostudy.threadcooperation;

import java.util.stream.Stream;

/**
* 協作模型:生產者---消費者方式一:
* 管程法
* @since JDK 1.8
* @date 2021/6/21
* @author Lucifer
*/
public class CoTestNo1 {
public static void main(String[] args) {

/*先建立緩衝區*/
SynContainer container = new SynContainer();

/*生產者*/
new Productor(container).start();

/*消費者*/
new Consumer(container).start();
}
}

/**
* 多執行緒生產者
*/
class Productor extends Thread{

/*對緩衝區進行操作*/
SynContainer container;

/*新增構造器*/
public Productor(SynContainer container){
super();
this.container = container;
}

/*重寫run方法*/
@Override
public void run(){

/*開始生產的執行緒程式碼*/
for (int i=0; i<100; i++){
System.out.println("生產--->" + i + "個饅頭");
container.push(new Streamedbun(i));
}
}
}

/**
* 多執行緒消費者
*/
class Consumer extends Thread{

/*對緩衝區進行操作*/
SynContainer container;

/*新增構造器*/
public Consumer(SynContainer container){
super();
this.container = container;
}

/*重寫run方法*/
@Override
public void run(){

/*開始生產的執行緒程式碼*/
for (int i=0; i<100; i++){
System.out.println("消費--->" + container.pop().id + "個饅頭");
}
}
}

/**
* 中間的緩衝區
*/
class SynContainer{

/*緩衝區當中要操作資料的容器--->陣列*/
Streamedbun[] buns = new Streamedbun[10]; //儲存資料的容器
int count = 0; // 計數器
/*
如果只是單純的不加入併發寫下面的方法還是會出現陣列越界的問題
解決辦法是加入併發synchronized
*/

//儲存方法
public synchronized void push(Streamedbun bun){

/*buns數字賦值*/
buns[count] = bun;
count++;
}

//獲取資料--->進棧原則,從最後一個位置去拿
public synchronized Streamedbun pop(){

/*拿出來數量就減少*/
count--;
Streamedbun bun = buns[count];

/*返回陣列*/
return bun;

}
}

/**
* 資料
*/
class Streamedbun{

/*資料*/
int id;

/*構造器*/
public Streamedbun(int id){
this.id = id;
}
}
解決了陣列越界問題和
package iostudy.threadcooperation;

import java.util.stream.Stream;

/**
* 協作模型:生產者---消費者方式一:
* 管程法
* 藉助緩衝區實現
* @since JDK 1.8
* @date 2021/6/21
* @author Lucifer
*/
public class CoTestNo1 {
public static void main(String[] args) {

/*先建立緩衝區*/
SynContainer container = new SynContainer();

/*生產者*/
new Productor(container).start();

/*消費者*/
new Consumer(container).start();
}
}

/**
* 多執行緒生產者
*/
class Productor extends Thread{

/*對緩衝區進行操作*/
SynContainer container;

/*新增構造器*/
public Productor(SynContainer container){
super();
this.container = container;
}

/*重寫run方法*/
@Override
public void run(){

/*開始生產的執行緒程式碼*/
for (int i=0; i<100; i++){
System.out.println("生產--->" + i + "個饅頭");
container.push(new Streamedbun(i));
}
}
}

/**
* 多執行緒消費者
*/
class Consumer extends Thread{

/*對緩衝區進行操作*/
SynContainer container;

/*新增構造器*/
public Consumer(SynContainer container){
super();
this.container = container;
}

/*重寫run方法*/
@Override
public void run(){

/*開始生產的執行緒程式碼*/
for (int i=0; i<100; i++){
System.out.println("消費--->" + container.pop().id + "個饅頭");
}
}
}

/**
* 中間的緩衝區
*/
class SynContainer{

/*緩衝區當中要操作資料的容器--->陣列*/
Streamedbun[] buns = new Streamedbun[10]; //儲存資料的容器
int count = 0; // 計數器
/*
如果只是單純的不加入併發寫下面的方法還是會出現陣列越界的問題
解決辦法是加入併發synchronized--->這樣就保證了緩衝區符合生產者、消費者模型的需求:有執行緒則無法在新增執行緒
如何保證資料的準確性?
只需要控制何時能消費:--->容器中是否存在資料。如果有資料,可以消費
如果沒有資料:--->等待
如何判斷?
檢視計數器是否為0
*/

//儲存方法
public synchronized void push(Streamedbun bun){

/*判斷何時能生產--->容器存在空間--->size==0*/
if (count==buns.length){

/*此時不能生產,只能等待*/
try {
this.wait(); //執行緒阻塞--->消費者通知生產,接觸等待
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}

}

/*buns數字賦值*/
buns[count] = bun;
count++;
/*通知消費者消費*/
this.notifyAll();

}

//獲取資料--->進棧原則,從最後一個位置去拿
public synchronized Streamedbun pop(){

/*判斷何時進行獲取資料的操作*/
if (count==0){

/*沒有資料,只有等待*/
//每個物件裡面都有一個wait方法
try {
this.wait(); //此時:執行緒阻塞--->生產者通知消費,解除阻塞--->會釋放鎖
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}

}

/*拿出來數量就減少*/
count--;
Streamedbun bun = buns[count];
/*消費完成通知生產者*/
this.notifyAll(); //存在空間了,可以喚醒對方生產了

/*返回陣列*/
return bun;

}
}

/**
* 資料
*/
class Streamedbun{

/*資料*/
int id;

/*構造器*/
public Streamedbun(int id){
this.id = id;
}
}