为了账号安全,请及时绑定邮箱和手机立即绑定

Java如何避免在循环中使用Thread.sleep()

Java如何避免在循环中使用Thread.sleep()

千万里不及你 2022-05-25 10:38:32
从我的主要我开始两个线程,称为生产者和消费者。两者都包含while(true)循环。生产者循环是 UDP 服务器,因此它不需要睡眠。我的问题出在消费者循环中。消费者循环从链接队列中删除对象并将其传递给函数以进行进一步处理。根据研究,在循环中使用线程睡眠不是一个好习惯,因为有时 O/S 不会在设定时间结束时释放。如果我在应用程序理想时删除线程睡眠,它会将 CPU 拖到 20% 到 30%。class Producer implements Runnable {    private DatagramSocket dsocket;    FError fer = new FError();    int port =1548;    ConcurrentLinkedQueue<String> queue;    Producer(ConcurrentLinkedQueue<String> queue){        this.queue = queue;     }    @Override    public void run() {        try {            // Create a socket to listen on the port.            dsocket = new DatagramSocket(port);            // Create a buffer to read datagrams into.            byte[] buffer = new byte[30000];            // Create a packet to receive data into the buffer            DatagramPacket packet = new DatagramPacket(buffer,            buffer.length);            while (true) {                try {                   // Wait to receive a datagram                    dsocket.receive(packet);                    //Convert the contents to a string,                    String msg = new String(buffer, 0, packet.getLength());                    int ltr = msg.length();                     // System.out.println("MSG =" + msg);                    if(ltr>4)                    {                        SimpleDateFormat sdfDate = new SimpleDateFormat  ("yyyy-MM-dd HH:mm:ss");//dd/MM/yyyy                        Date now = new Date();                        String strDate = sdfDate.format(now);                        //System.out.println(strDate);                        queue.add(msg + "&" + strDate);                     // System.out.println("MSG =" + msg);                    }                  // Reset the length of the packet before reusing it.                   packet.setLength(buffer.length);                }         } 
查看完整描述

3 回答

?
饮歌长啸

TA贡献1951条经验 获得超3个赞

而不是让 Consumerextend Runnable你可以改变你的代码来合并一个ScheduledExecutorService每半秒运行一次队列轮询而不是让线程休眠的代码。这方面的一个例子是


public void schedule() {

    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    executor.scheduleAtFixedRate(() -> {

        String str;

        try {

            while ((str = queue.poll()) != null) {

                call(str);  // do further processing

            }

        } catch (IOException e) {

            ferpt.felog("svr class", "consumer", "consumer thread", e.getClass().getName() + ": " + e.getMessage());

        }

    }, 0, 500, TimeUnit.MILLISECONDS);

}


查看完整回答
反对 回复 2022-05-25
?
潇湘沐

TA贡献1816条经验 获得超6个赞

解决您的问题的正确方法是使用阻塞队列。它为您提供了几个优势:

  • 不浪费cpu忙等待

  • 容量有限 - 假设你有一个快速的生产者,但一个缓慢的消费者 -> 如果队列的大小不受限制,那么你的应用程序很容易达到 OutOfMemory 条件

这是一个小演示,您可以使用它:

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;


public class ProdConsTest {

    public static void main(String[] args) throws InterruptedException {

        final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

        final Runnable producer = () -> {

            for (int i = 0; i < 1000; i++) {

                try {

                    System.out.println("Producing: " + i);

                    queue.put(i);


                    //Adjust production speed by modifying the sleep time

                    Thread.sleep(100);

                } catch (InterruptedException e) {

                    //someone signaled us to terminate

                    break;

                }

            }

        };


        final Runnable consumer = () -> {

            while (true) {

                final Integer integer;

                try {

                    //Uncomment to simulate slow consumer:

                    //Thread.sleep(1000);


                    integer = queue.take();

                } catch (InterruptedException e) {

                    //someone signaled us to terminate

                    break;

                }

                System.out.println("Consumed: " + integer);

            }

        };



        final Thread consumerThread = new Thread(consumer);

        consumerThread.start();


        final Thread producerThread = new Thread(producer);

        producerThread.start();


        producerThread.join();

        consumerThread.interrupt();

        consumerThread.join();

    }

}

现在取消注释sleep()消费者并观察应用程序发生了什么。如果您正在使用基于计时器的解决方案,例如建议的解决方案,ScheduledExecutorService或者您正忙于等待,那么使用快速生产者,队列将无法控制地增长并最终导致您的应用程序崩溃


查看完整回答
反对 回复 2022-05-25
?
月关宝盒

TA贡献1772条经验 获得超5个赞

当有新消息时,让消费者wait()在一个对象上都可以访问,并让生产者在这个对象上监听。notify()然后,消费者应该删除所有消息,而不仅仅是示例中的单个消息。



查看完整回答
反对 回复 2022-05-25
  • 3 回答
  • 0 关注
  • 717 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号