[英]Java thread producer and consumer program issue
我正在嘗試Java線程生產者和使用者程序。 但是使用者線程總是進入等待狀態。
我無法調試為什么使用者線程始終進入等待狀態或生產者未通知使用者線程的問題
請幫我解決這個問題。 程序如下。
溝通者階層稱生產者階層和消費者階層
public class Communicator {
Thread t = null;
Thread t1 = null;
public void runThread() {
Producer p = new Producer();
Consumer c = new Consumer(p);
t = new Thread(p);
t1 = new Thread(c);
t.start();
t1.start();
Thread tr = new Thread() {
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("t::::::::::::: " + t.getState());
System.out.println("t1::::::::::::: " + t1.getState());
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
tr.start();
}
public static void main(String[] args) {
Communicator c = new Communicator();
c.runThread();
}
}
這是生產者類,它將數據附加到stringbuffer中並通知消費者類
public class Producer extends Thread {
public StringBuffer sb;
public Producer() {
sb = new StringBuffer();
}
public void run() {
synchronized (sb) {
try {
System.out.println("Bala");
sb.append("murugan");
sb.notify();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
下面是消費者類代碼。 它等待接收生產者類的通知。
public class Consumer extends Thread {
public Producer p;
public Consumer(Producer p) {
this.p = p;
}
public void run(){
synchronized (p.sb) {
try {
p.sb.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(p.sb);
}
}
}
Producer
已經被終止,並且它已經在Consumer
調用wait()
之前調用了notify()
wait()
。
由於Producer
和Consumer
extends
Thread
,因此將Communicator
類更新為:
public class Communicator {
public void runThread() {
final Producer p = new Producer();
final Consumer c = new Consumer(p);
p.start();
c.start();
Thread tr = new Thread() {
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("t::::::::::::: " + p.getState());
System.out.println("t1::::::::::::: " + c.getState());
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
tr.start();
}
public static void main(String[] args) {
Communicator c = new Communicator();
c.runThread();
}
}
如果Producer
尚未終止[ if (p.getState() != Thread.State.TERMINATED)
],則這是Consumer
唯一等待的時間:
public class Consumer extends Thread {
public Producer p;
public Consumer(Producer p) {
this.p = p;
}
public void run() {
synchronized (p.sb) {
try {
if (p.getState() != Thread.State.TERMINATED) {
p.sb.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(p.sb);
}
}
}
當前的代碼很少有問題,其中Consumer線程始終處於等待狀態,而Producer已經終止。
同樣,您的StringBuffer
對象需要是volatile
以便生產者線程寫操作將被刷新並可供其他線程使用。
除此之外,我還修改了您的Producer
和Consumer
代碼,使其更加真實(都在while
循環中運行,一個循環生成一些數據,另一個循環接收數據),如下所示:(我還添加了1秒的睡眠時間來運行事物以較慢的速度,以便您可以更好地理解事物):
消費類:
public class Producer extends Thread {
public volatile StringBuffer sb;
public Producer() {
sb = new StringBuffer();
sb.append("");
}
public void run() {
synchronized (sb) {
try {
while(true) {
Thread.sleep(1000);
if(sb.toString().equals("")) {
sb.append("murugan");
System.out.println(" producing sb completed *** ");
sb.notify();
} else {
sb.wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
消費類:
public class Consumer extends Thread {
public Producer p;
public Consumer(Producer p) {
this.p = p;
}
public void run(){
synchronized (p.sb) {
try {
while(true) {
Thread.sleep(1000);
if(p.sb.toString().equals("")) {
p.sb.wait();
} else {
String str = p.sb.toString();
System.out.println(" consuming sb completed **** "+str);
p.sb.replace(0, str.length(), "");
p.sb.notify();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(p.sb);
}
}
}
對於您的問題,“我無法調試為什么使用者線程始終進入等待狀態或生產者未通知使用者線程的問題”。 實際上,您的消費者並不總是處於等待狀態。 您可以將Thread.sleep(1000);放在p.sb.wait()之前; 在您的Consumer類中,您一次可以看到“ consumerThread :::::::::::::::可運行”。 恕我直言,您的使用者代碼運行得太快而無法獲得等待狀態,因此您錯過了可運行狀態。 您可以從其他答案中學到更多。
這不是一個答案,而是一個建議……您可以使用BlockingQueue簡化將數據從生產者傳輸到消費者的整個邏輯。 所有等待和通知將消失!
Producer(s) send data to be consumed calling BlockingQueue.offer(String)
Consumer(s) wait (blocked) for data calling BlockingQueue.pool();
根據您的代碼, Consumer Thread
等待Producer
notify
有關StringBuffer
附加的字符串的信息。
Producer
線程有機會獲取shared StringBuffer object
上的鎖( 進入synchronized block
),那么Consumer Thread
將進入Blocked state
( 將無法進入synchronized block
),因為它也是Lock的競爭者(兩者都競爭獲取同一共享庫上的鎖)。 synchronized block
並終止。 請注意,通知代碼不會產生任何影響,因為消費者線程尚未等待共享對象,因為它尚未進入同步塊 Consumer thread
有機會獲得lock
並進入synchronized block
它waits
某個Consumer thread
在共享對象上發出通知。 但是由於生產者已經終止,所以沒有人將通知發送給Consumer thread
並且該通知仍處於Waiting
狀態。 修復 :就您而言,您可以簡單地確保首先啟動Consumer thread
並在Producer線程之前獲取鎖。 為此,您可以在啟動使用者線程之后使主線程休眠一段時間。
t = new Thread(p);
t1 = new Thread(c);
t1.start();
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
t.start();
關鍵點 :如果只有2個線程,則一個線程應調用notify
和wait
。 其他線程在收到通知后,只有競爭Lock的線程才能獲取該鎖並完成其工作。 工作完成后,它應調用notify並等待另一個線程完成工作並在完成后發出通知。 這樣,兩個線程都將有機會一個接一個地完成其工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.