JAVA线程之生产者消费者问题
復(fù)習(xí)下JAVA線程基礎(chǔ)知識(shí):
1、線程的狀態(tài):
創(chuàng)建狀態(tài):創(chuàng)建了線程對象,此時(shí)線程有了相應(yīng)的內(nèi)存空間和其他資源,但處于不可運(yùn)行狀態(tài)。
就緒狀態(tài):線程對象調(diào)用start()方法啟動(dòng)線程,進(jìn)入就緒狀態(tài),此時(shí)線程進(jìn)入線程隊(duì)列排隊(duì),此時(shí)已經(jīng)具備運(yùn)行的條件。
運(yùn)行狀態(tài):線程搶占到cpu資源,此時(shí)線程進(jìn)入運(yùn)行狀態(tài),自動(dòng)調(diào)用run()方法。
阻塞狀態(tài):正在運(yùn)行的線程,讓出cpu資源并暫時(shí)中止自己的執(zhí)行,進(jìn)入阻塞狀態(tài),在可執(zhí)行狀態(tài)可調(diào)用sleep()、suspend()、wait()等方法進(jìn)入阻塞狀態(tài)
,阻塞中不能進(jìn)入線程排隊(duì)搶占資源,只有阻塞消除后才能進(jìn)入就緒狀態(tài)。
死亡狀態(tài):線程調(diào)用stop()方法或run()執(zhí)行結(jié)束后,即處于死亡狀態(tài)
2、常用API
Thread.currentThread() 當(dāng)前線程
Thread.isAlive 對象方法, 線程是否啟動(dòng)
Thread.join 對象方法,線程強(qiáng)制運(yùn)行,其他線程必須等到該線程運(yùn)行完畢后才能繼續(xù)執(zhí)行
Thread.sleep靜態(tài)方法,當(dāng)前線程休眠
Thread.interrup靜態(tài)方法讓,t中斷正在執(zhí)行的線程,會(huì)拋異常
Thread.setDaemon(true) 對象方法,設(shè)置此線程在后臺(tái)運(yùn)行
Thread線程的優(yōu)先級,Thread.MIN_PRIORITY 1,Thread.NORM_PRIORITY 5,Thread.MAX_PRIORITY 10,mian線程 是5
Thread.yield()靜態(tài)方法,線程的禮讓,本線程釋放資源,和其他線程一起再次公平競爭獲取資源
3、實(shí)現(xiàn)Runnable接口相對于繼承Thread類來說,有什么優(yōu)勢
1、適合多個(gè)相同程序代碼去處理同一資源
2、可以避免由于Java單繼承帶來的局限
3、增強(qiáng)了程序的健壯性,代碼能夠被多個(gè)線程共享,代碼與數(shù)據(jù)獨(dú)立。
生產(chǎn)者消費(fèi)者問題的引出:
生產(chǎn)者不斷的往倉庫中生產(chǎn)貨物,貨物裝滿時(shí)等消費(fèi)者消費(fèi)再生產(chǎn),消費(fèi)者不斷的從倉庫中消費(fèi)貨物,倉庫為空時(shí)等生產(chǎn)者生產(chǎn)后再消費(fèi)
參照網(wǎng)上的寫法,自己寫了一個(gè)
package com.lcx.test;import java.util.ArrayList; import java.util.List;/*** 生產(chǎn)者消費(fèi)者問題* 生產(chǎn)者不斷的往倉庫中生產(chǎn)貨物,貨物裝滿時(shí)等消費(fèi)者消費(fèi)再生產(chǎn),消費(fèi)者不斷的從倉庫中消費(fèi)貨物,倉庫為空時(shí)等生產(chǎn)者生產(chǎn)后再消費(fèi)* 倉庫類,存放貨物的載體,倉庫有最大容量。* 生產(chǎn)的貨物數(shù)量+原有的數(shù)量 超過容量 就必須停止生產(chǎn)進(jìn)入等待 讓消費(fèi)者消費(fèi)消費(fèi)后喚醒生產(chǎn)者。* 消費(fèi)的貨物數(shù)量 超過現(xiàn)有貨物 就必須停止消費(fèi)進(jìn)入等待 讓生產(chǎn)者生產(chǎn)貨物后喚醒消費(fèi)者。* 生產(chǎn)者類,負(fù)責(zé)生產(chǎn)* 消費(fèi)者類,負(fù)責(zé)消費(fèi)* wait() / notify() 使用這個(gè)實(shí)現(xiàn)* @author Administrator*/ public class Interview_2_ProductConsumer {public static void main(String[] args) {//生產(chǎn)者、消費(fèi)者公用倉庫資源Storehouse store = new Storehouse();Producter p1 = new Producter(10, store);Producter p2 = new Producter(20, store);Producter p3 = new Producter(30, store);Producter p4 = new Producter(50, store);Producter p5 = new Producter(50, store);Consumer c1 = new Consumer(20, store);Consumer c2 = new Consumer(10, store);Consumer c3 = new Consumer(50, store);Consumer c4 = new Consumer(60, store); // Consumer c5 = new Consumer(100, store);p1.start();p2.start();p3.start();p4.start();p5.start();c1.start();c2.start();c3.start();c4.start(); // c5.start();} } /*** 倉庫類* @author Administrator**/ class Storehouse{//倉庫存儲(chǔ)最大數(shù)private static final int maxNum = 100;//貨物載體private List<Object> goods = new ArrayList<Object>(); /*** 生產(chǎn)num個(gè)貨物* @param num*/public void product(int num){synchronized (goods) { // System.out.print("開始生產(chǎn),");/** 生產(chǎn)的數(shù)量超過倉庫容量,一定要用while,因?yàn)椴环蠗l件時(shí)進(jìn)入線程等待(此時(shí)等待消費(fèi)者消費(fèi)),* 消費(fèi)者消費(fèi)后,喚醒生產(chǎn)者,生產(chǎn)者 還要繼續(xù)判斷是否可以生產(chǎn),不能生產(chǎn)還得進(jìn)入線程等待*/while (goods.size()+num>maxNum) {System.out.println("倉庫現(xiàn)有:"+goods.size()+",生產(chǎn):"+num+",超過最大容量"+maxNum+",無法進(jìn)行生產(chǎn)");try {goods.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int i=0;i<num;i++){goods.add(new Object());}System.out.println("生產(chǎn):"+num+",現(xiàn)有貨物:"+goods.size());goods.notifyAll();}}/*** 消費(fèi)num個(gè)貨物* @param num*/public void consumer(int num){synchronized (goods) { // System.out.print("開始消費(fèi),");//消費(fèi)的數(shù)量超過倉庫容量while(num>goods.size()) {System.out.println("倉庫現(xiàn)有:"+goods.size()+",消費(fèi):"+num+",超過現(xiàn)有量無法進(jìn)行消費(fèi)");try {goods.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int i=0;i<num;i++){goods.remove(goods.size()-1);}System.out.println("消費(fèi):"+num+",現(xiàn)有貨物:"+goods.size());goods.notifyAll();}} } /*** 生產(chǎn)者* @author Administrator**/ class Producter extends Thread{//生產(chǎn)貨物數(shù)量private int num;private Storehouse store;public Producter(int num, Storehouse store) {super();this.num = num;this.store = store;}@Overridepublic void run() {store.product(num);} } /*** 消費(fèi)者* @author Administrator*/ class Consumer extends Thread{//消費(fèi)貨物數(shù)量private int num;private Storehouse store;public Consumer(int num, Storehouse store) {super();this.num = num;this.store = store;}@Overridepublic void run() {store.consumer(num);} } 結(jié)果截圖
消費(fèi)完了,還有剩余的貨物,如果將消費(fèi)者c5放開,結(jié)果如下
由于生產(chǎn)者都生產(chǎn)完了,還不夠消費(fèi)者消費(fèi),故 消費(fèi)者進(jìn)入等待狀態(tài),等待生產(chǎn)者生產(chǎn)后喚醒消費(fèi)者消費(fèi),故會(huì)出現(xiàn)這種情況。
網(wǎng)上有JAVA 面試題一道,類似生產(chǎn)者消費(fèi)者問題
編程實(shí)現(xiàn):線程A向隊(duì)列Q中不停寫入數(shù)據(jù),線程B從隊(duì)列Q中不停讀取數(shù)據(jù)(只要Q中有數(shù)據(jù))。
代碼實(shí)現(xiàn)如下:
package com.lcx.test;import java.util.ArrayList; import java.util.List;/***2.編程實(shí)現(xiàn):線程A向隊(duì)列Q中不停寫入數(shù)據(jù),線程B從隊(duì)列Q中不停讀取數(shù)據(jù)(只要Q中有數(shù)據(jù))。*實(shí)質(zhì)和生產(chǎn)者和消費(fèi)者問題一樣,* 情況一:如果要求先壓入數(shù)據(jù)后馬上彈出然后再才壓入,就需要一個(gè)標(biāo)志來確定是否讀入或者寫出了。* 此時(shí),彈出和壓入總是成對出現(xiàn)* 情況二:如果只要求,隊(duì)列不為空就可彈出,隊(duì)列沒有滿就可壓入數(shù)字,就只需判斷當(dāng)前壓入的數(shù)字有沒有超過隊(duì)列的最大長度 即可壓入,當(dāng)前隊(duì)列不為空才彈出。* @author Administrator*/ public class Interview_2_ReadWrite {public static void main(String[] args) {Queue queue = new Queue(10);Pusher p1 = new Pusher(queue, 1);Pusher p2 = new Pusher(queue, 2);Pusher p3 = new Pusher(queue, 3);Pusher p4 = new Pusher(queue, 4);Poper po1 = new Poper(queue);Poper po2 = new Poper(queue);Poper po3 = new Poper(queue);Poper po4 = new Poper(queue);p1.start();p2.start();p3.start();p4.start();po1.start(); po2.start(); po3.start(); po4.start(); } } class Queue{//標(biāo)志位,true 可彈出數(shù)字,false 可壓入數(shù)字private boolean flag ;private final int maxLength;private List<Integer> queue = new ArrayList<Integer>() ;public Queue(int maxLength) {super();this.maxLength = maxLength;}/*** 往隊(duì)列中壓數(shù)字*/public void push(int num){//情況一synchronized (queue) {//壓入的數(shù)字超過最大的下標(biāo)while(flag){System.out.println("還未彈出數(shù)字,暫時(shí)不能壓入數(shù)字");try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}queue.add(num);System.out.println("壓入,數(shù)字下標(biāo)index ="+ (queue.size()-1) + ",數(shù)字:" + queue.get(queue.size()-1));flag = true;queue.notifyAll();}//情況二/*synchronized (queue) {// 壓入的數(shù)字超過最大的下標(biāo)while (queue.size()+1 > maxLength) {System.out.println("隊(duì)列已滿,無法壓入數(shù)字");try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}queue.add(num);System.out.println("壓入,數(shù)字下標(biāo)index ="+ (queue.size()-1) + ",數(shù)字:" + queue.get(queue.size()-1));queue.notifyAll();}*/}/*** 從隊(duì)列中取數(shù)字*/public void pop(){//情況一synchronized (queue) {//取出的數(shù)字下標(biāo)非法時(shí)while(!flag){System.out.println("還未壓入數(shù)字,暫時(shí)不能彈出數(shù)字");try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("彈出,數(shù)字下標(biāo)index ="+ (queue.size()-1) + ",數(shù)字:" + queue.get(queue.size()-1));queue.remove(queue.size()-1);flag = false;queue.notifyAll();}//情況二/*synchronized (queue) {//隊(duì)列為空是while (queue.size() == 0 ) {System.out.println("隊(duì)列已空,無法彈出數(shù)字");try {queue.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("彈出,數(shù)字下標(biāo)index ="+ (queue.size()-1) + ",數(shù)字:" + queue.get(queue.size()-1));queue.remove(queue.size()-1);queue.notifyAll();}*/} } class Pusher extends Thread{private Queue queue;private int num;public Pusher(Queue queue,int num) {super();this.num = num;this.queue = queue;}@Overridepublic void run() {queue.push(num);}} class Poper extends Thread{private Queue queue;public Poper(Queue queue) {super();this.queue = queue;}@Overridepublic void run() {queue.pop();}}情況一結(jié)果如下:情況二截圖:
總結(jié)
以上是生活随笔為你收集整理的JAVA线程之生产者消费者问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala-Unit6-final/ty
- 下一篇: 字符串:BF算法