[英]Java how to avoid using Thread.sleep() in a loop
From my main I am starting two threads called producer and consumer.从我的主要开始,我开始了两个名为生产者和消费者的线程。 Both contains
while(true)
loop.两者都包含
while(true)
循环。 Producer loop is UDP Server hence it does not require sleep.生产者循环是 UDP 服务器,因此它不需要睡眠。 My problem is in the Consumer loop.
我的问题出在消费者循环中。 Consumer loop remove the objects from the linked queue and pass it on to a function for further processing.
消费者循环从链接队列中删除对象并将其传递给函数以进行进一步处理。 From what researched it is not a good practice to use thread sleep in a loop as at times O/S will not release at end of set time.
根据研究,在循环中使用线程睡眠不是一个好习惯,因为有时 O/S 不会在设置时间结束时释放。 If I remove thread sleep when the application is ideal it drags CPU to 20 to 30%.
如果我在应用程序理想时删除线程睡眠,它会将 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);
} catch (IOException e) {
fer.felog("svr class", "producer", "producer thread",e.getClass().getName() + ": " + e.getMessage());
dsocket.close();
break;
}
}
} catch (SocketException e) {
fer.felog("svr class", "producer","Another App using the udp port " + port, e.getClass().getName() + ": " + e.getMessage());
}
}
}
class Consumer implements Runnable {
String str;
ConcurrentLinkedQueue<String> queue;
Consumer(ConcurrentLinkedQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
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());
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ferpt.felog("svr class", "consumer","sleep", ex.getClass().getName() + ": " + ex.getMessage());
}
}
}
}
Instead of making Consumer extend Runnable
you could change your code to incorporate a ScheduledExecutorService
which runs the polling of the queue every half a second instead of making the thread sleep.您可以更改代码以合并
ScheduledExecutorService
,而不是让 Consumer extend Runnable
,该服务每半秒运行一次队列轮询,而不是让线程休眠。 An example of this would be这方面的一个例子是
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);
}
The proper solution to your problem is to use a blocking queue.解决问题的正确方法是使用阻塞队列。 It gives you several advantages:
它为您提供了几个优势:
Here is a small demo, which you can play with:这是一个小演示,您可以使用它:
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();
}
}
Now uncomment the sleep()
in the consumer and observe what happems with the application.现在取消消费者中的
sleep()
注释并观察应用程序发生了什么。 If you were using a timer based solution such as the proposed ScheduledExecutorService
or you were busy waiting, then with fast producer, the queue would grow uncontrollably and eventually crash your application如果您正在使用基于计时器的解决方案,例如建议的
ScheduledExecutorService
或者您正忙于等待,那么使用快速生产者,队列将无法控制地增长并最终使您的应用程序崩溃
Let the consumer wait()
on an object that both have access to, and let the producer notify()
listeners on this object when there's new messages.让消费者
wait()
在一个都可以访问的对象上,让生产者notify()
在有新消息时监听这个对象。 The consumer should remove all messages then, not just a single one like in the example.消费者应该删除所有消息,而不是像示例中那样只删除一条消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.