Проблема производителя потока Java и программы-потребителя

Я пробую производителя потока 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();
    }
}

Это класс производителя, который добавляет данные в строковый буфер и уведомляет класс потребителя.

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);
        }
    }


}

person user3509105    schedule 25.11.2016    source источник
comment
Прежде чем перейти к wait() в классе Consumer, вы должны выполнить свою бизнес-логику для обработки материала в строковом буфере. Вы должны перейти wait() только в том случае, если нет данных, доступных для обработки.   -  person Alex Suo    schedule 25.11.2016
comment
Этот вопрос может быть полезен: stackoverflow.com/questions/37683895/. Он удаляет ожидание и уведомляет с помощью BlokcingQueues. Заменить Interger строкой   -  person Ravindra babu    schedule 30.11.2016
comment
@ user3509105, пожалуйста, обратитесь к моему ответу ниже. Надеюсь, это будет полезно. Метод notify() пробуждает только "подходящие потоки", которые в настоящее время не активны, но ожидают уведомления, чтобы они могли получить блокировку. Надеюсь, это будет полезно.   -  person nits.kk    schedule 04.02.2017


Ответы (5)


Есть несколько проблем с вашим текущим кодом, в котором поток-потребитель всегда находится в состоянии ожидания, тогда как производитель уже завершен.

Кроме того, ваш объект 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);
            }
        }
    }
person developer    schedule 25.11.2016

на ваш вопрос: «Я не могу отладить проблемы, почему потребительский поток всегда переходит в состояние ожидания или производитель не уведомляет потребительский поток». На самом деле ваш потребитель не всегда находится в состоянии ожидания. Вы можете просто поставить Thread.sleep(1000);before p.sb.wait(); в вашем классе Consumer вы можете увидеть «consumerThread:::::::::::::: RUNNABLE» один раз. ИМХО, ваш потребительский код работает слишком быстро, чтобы получить статус ожидания, поэтому вы пропускаете статус запуска. Вы можете узнать больше из других ответов.

person yuxh    schedule 25.11.2016

Producer уже завершен, и он уже вызвал notify() до того, как Consumer вызвал 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);
        }

    }
}
person Jessie Brian Revil    schedule 25.11.2016

Это не ответ, а предложение... Вы можете упростить всю логику, используя BlockingQueue для передачи данных от производителей к потребителям. Все ожидания и уведомления исчезнут!

Producer(s) send data to be consumed calling BlockingQueue.offer(String)

Consumer(s) wait (blocked) for data calling BlockingQueue.pool();
person VeryNiceArgumentException    schedule 25.11.2016

Согласно вашему коду, Consumer Thread ждет от Producer до notify о строке, добавленной в StringBuffer.

  1. Если поток Producer получит возможность получить блокировку потока shared StringBuffer object (он входит в поток synchronized block), то поток Consumer Thread войдет в поток Blocked state(не сможет войти в поток synchronized block), поскольку его также конкурент за блокировку (оба конкурируют за получение блокировки на одном и том же общем объекте).
  2. Поток-производитель завершает свое выполнение, покидает synchronized block и завершается. Обратите внимание, что код уведомления не окажет никакого влияния, так как поток-потребитель еще не ожидает общий объект, так как он еще не вошел в синхронизированный блок
  3. Consumer thread получает возможность получить lock и ввести synchronized block It waits для того, чтобы кто-то уведомил об общем объекте. Но поскольку Producer уже закрыт, никто не уведомляет Consumer thread, и он остается в состоянии Waiting.

Исправить: в вашем случае вы можете просто убедиться, что Consumer thread запускается первым и получает блокировку до потока Producer. Для этого вы можете заставить основной поток спать некоторое время после запуска потока Consumer.

t = new Thread(p);
t1 = new Thread(c);
t1.start();
try {
        Thread.sleep(1000);
    }catch (InterruptedException e) {
        e.printStackTrace();
    }
t.start();

Ключевой момент. Если у вас всего 2 потока, один поток должен вызывать notify и wait. Другой поток после получения уведомления, и только поток, конкурирующий за блокировку, получит блокировку и выполнит свою работу. По завершении своей работы он должен вызвать уведомление и будет ждать, пока другой поток выполнит задание, и выдаст уведомление после завершения. Таким образом, оба потока получат возможность выполнять свою работу один за другим.

person nits.kk    schedule 30.11.2016