从我的主要我开始两个线程称为生产者和消费者。两者都包含while(true)
循环。生产者循环是UDP服务器,因此它不需要睡眠。我的问题出现在Consumer循环中。使用者循环从链接队列中删除对象并将其传递给函数以进行进一步处理。从研究结果来看,在循环中使用线程休眠不是一个好习惯,因为有时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);
} 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());
}
}
}
}
您可以更改代码以包含extend 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);
}
每隔半秒运行一次队列轮询,而不是让线程休眠。这方面的一个例子是
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
的注释,并观察应用程序发生的情况。如果您使用的是基于计时器的解决方案,例如建议的wait()
或者您正忙着等待,那么对于快速生产者,队列将无法控制地增长并最终导致应用程序崩溃
让消费者notify()
访问一个既可以访问的对象,也可以让生产者qazxswpoi监听这个对象时有新消息。消费者应该删除所有消息,而不仅仅是示例中的单个消息。