繁体   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