亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

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 關注
  • 667 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號