簡體   English   中英

Java線程生產者和使用者程序問題

[英]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()

由於ProducerConsumer 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以便生產者線程寫操作將被刷新並可供其他線程使用。

除此之外,我還修改了您的ProducerConsumer代碼,使其更加真實(都在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附加的字符串的信息。

  1. 如果Producer線程有機會獲取shared StringBuffer object上的鎖( 進入synchronized block ),那么Consumer Thread將進入Blocked state將無法進入synchronized block ),因為它也是Lock的競爭者(兩者都競爭獲取同一共享庫上的鎖)。
  2. 生產者線程完成其執行,離開synchronized block並終止。 請注意,通知代碼不會產生任何影響,因為消費者線程尚未等待共享對象,因為它尚未進入同步塊
  3. Consumer thread有機會獲得lock並進入synchronized blockwaits某個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個線程,則一個線程應調用notifywait 其他線程在收到通知后,只有競爭Lock的線程才能獲取該鎖並完成其工作。 工作完成后,它應調用notify並等待另一個線程完成工作並在完成后發出通知。 這樣,兩個線程都將有機會一個接一個地完成其工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM