java用while循环设计轮询线程的性能问题

轮询线程在开发过程中的应用是比较广泛的,在这我模拟一个场景,有一个队列和轮询线程,主线程往队列中入队消息,轮询线程循环从队列中读取消息并打印消息内容。有点类似Android中Handler发送消息。

首先定义一个Message类。

public class Message {
private String content;
public Message(String content)
{
this.content=content;
}
public void display(){
System.out.println(content);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这个类很简单,在构造的时候传入消息内容,display()方法输出打印消息内容。

接下来定义一个轮询线程,一开始蠢萌的我这么写

public class PollingThread extends Thread implements Runnable {
public static Queue<Message> queue = new LinkedTransferQueue<Message>(); @Override
public void run() {
while (true) {
while (!queue.isEmpty()) {
queue.poll().display();
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这个轮询线程功能很简单,一直不停的轮询队列,一旦队列中有消息进入,就将它出队并调用display()方法输出内容。

接下来在Main()方法中循环创建消息将它放入队列

public class Main {
public static void main(String[] args){
PollingThread pollingThread=new PollingThread();
pollingThread.start();
int i=1;
while(true)
{
PollingThread.queue.offer(new Message("新消息"+i));
i++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行结果

新消息1
新消息2
新消息3
新消息4
新消息5
新消息6
新消息7
新消息8
新消息9
新消息10
新消息11
新消息12
新消息13
新消息14
新消息15
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

虽然这么做,功能是实现了,可是我们来看下cpu占用率

程序刚编译启动的时候cpu占用率到了100%,开始运行后一直处于44%左右。这个占用率还是比较高的,那么我们来分析一下这个轮询线程,假设一直没有消息入队,或者消息入队的间隔时间比较长的话,它就会循环的去执行while(!queue.isEmpty())判断队列是否为空,其实这个判断操作是非常耗性能的。我们应该把这个轮询线程设计的更合理一点。那么怎样设计比较合理呢?既然循环对队列判空是比较浪费性能的操作,那么我们如果可以让这个轮询线一开始处于阻塞状态,主线程在每次入队消息的时候通知轮询线程循环出队输出消息内容,当队列为空的时候轮询线程又自动的进入阻塞状态,就可以避免轮询线程死循环对队列判空。接下来我们改造一下轮询线程和主线程的代码

public class PollingThread extends Thread implements Runnable {
public static Queue<Message> queue = new LinkedTransferQueue<Message>(); @Override
public void run() {
while (true) {
while (!queue.isEmpty()) {
queue.poll().display();
}
//把队列中的消息全部打印完之后让线程阻塞
synchronized (Lock.class)
{
try {
Lock.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
public class Main {
public static void main(String[] args){
PollingThread pollingThread=new PollingThread();
pollingThread.start();
int i=1;
while(true)
{
PollingThread.queue.offer(new Message("新消息"+i));
i++;
//有消息入队后激活轮询线程
synchronized (Lock.class)
{
Lock.class.notify();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这时候再来运行一下

运行结果

新消息1
新消息2
新消息3
新消息4
新消息5
新消息6
新消息7
新消息8
新消息9
新消息10
新消息11
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

再来看看cpu占用率

轮询线程经过改造后cpu占用率基本稳定在11%,比之前44%下降了不少。

所以,在编写轮询线程的时候,尽量用通知的方式去让轮询线程执行操作,避免重复的条件判断造成的性能浪费。

http://blog.csdn.net/q15858187033/article/details/60583631

java用while循环设计轮询线程的性能问题的更多相关文章

  1. 基于springboot实现轮询线程自动执行任务

    本文使用: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时 ...

  2. 为什么JAVA要提供 wait/notify 机制?是为了避免轮询带来的性能损失

    wait/notify  机制是为了避免轮询带来的性能损失. 为了说清道理,我们用“图书馆借书”这个经典例子来作解释. 一本书同时只能借给一个人.现在有一本书,图书馆已经把这本书借了张三. 在简单的s ...

  3. Java实现负载均衡算法--轮询和加权轮询

    1.普通轮询算法 轮询(Round Robin,RR)是依次将用户的访问请求,按循环顺序分配到web服务节点上,从1开始到最后一台服务器节点结束,然后再开始新一轮的循环.这种算法简单,但是没有考虑到每 ...

  4. Apollo 3 定时/长轮询拉取配置的设计

    前言 如上图所示,Apollo portal 更新配置后,进行轮询的客户端获取更新通知,然后再调用接口获取最新配置.不仅仅只有轮询,还有定时更新(默认 5 分钟一次).目的就是让客户端能够稳定的获取到 ...

  5. Java实现平滑加权轮询算法--降权和提权

    上一篇讲了普通轮询.加权轮询的两种实现方式,重点讲了平滑加权轮询算法,并在文末留下了悬念:节点出现分配失败时降低有效权重值:成功时提高有效权重值(但不能大于weight值). 本文在平滑加权轮询算法的 ...

  6. 如何从线程返回信息——轮询、回调、Callable

    考虑有这样一个LiftOff类: /** * 类LiftOff.java的实现描述:显示发射之前的倒计时 * * @author wql 2016年9月21日 下午1:46:46 */ public ...

  7. 权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现2

    权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现 ----参考Nginx中负载均衡算法实现 与上一遍博客 http://www.cnblogs.com/hu ...

  8. 权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现

    权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现 import java.math.BigInteger; import java.util.ArrayLi ...

  9. [置顶] Android AlarmManager实现不间断轮询服务

    在消息的获取上是选择轮询还是推送得根据实际的业务需要来技术选型,例如对消息实时性比较高的需求,比如微博新通知或新闻等那就最好是用推送了.但如果只是一般的消息检测比如更新检查,可能是半个小时或一个小时一 ...

随机推荐

  1. scikit-learn 学习笔记-- Generalized Linear Models (三)

    Bayesian regression 前面介绍的线性模型都是从最小二乘,均方误差的角度去建立的,从最简单的最小二乘到带正则项的 lasso,ridge 等.而 Bayesian regression ...

  2. NAT 穿透

    /********************************************************************************* * NAT 穿透 * 说明: * ...

  3. JAVA使用ItextPDF

    1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...

  4. 如何在Oracle官网下载java的JDK最新版本和历史版本

    官网上最显眼位置只显示了Java SE的JDK的最新版本下载链接,因为都是英文,如果英文不是很好,寻找之前的JDK版本需要很长时间,而且未必能在那个隐蔽的位置找到之前版本列表. 今天小编来给你详细讲解 ...

  5. UVALive 5135 Mining Your Own Bussiness【tarjan点双】

    LINK1 LINK2 题目大意 给你一个无向连通图,让你给一些点染上黑色,需要满足染色之后,断开任意一个节点,要满足任意一个联通块中剩下的节点中至少有一个黑点 思路 一开始想的是把每一个点双联通分量 ...

  6. scrapy多线程文件下载

    在爬取数据时有时候有些文件数据需要爬取下载下来使用多线程下载可以让程序跑的更快点. scrapy中有个扩展可以使用扩展模块来实现下载. 在自己的spider中加入 custom_settings cl ...

  7. 重新学习之spring第三个程序,整合struts2+spring

    第一步:导入Struts2jar包+springIOC的jar包和Aop的Jar包 第二步:建立applicationContext.xml文件+struts.xml文件+web.xml文件 web. ...

  8. vs2013突然没有代码提示功能了。

    工具->选项->文本编辑器->C++ ->高级->禁用IntelliSense设置 false 然后选确定.

  9. socket编程---TCP

    服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接.在这时如果有个客户端初始化一个Socket,然后连接服务器(connec ...

  10. Javascript 全局函数是 window 的函数

    比如以下函数,看起来不属于任何对象,但它是一个全局对象. 它属于 HTML页面的函数. function myFunction(a, b){ return a * b; } window.myFunc ...