zoukankan      html  css  js  c++  java
  • PriorityBlockingQueue 和 Executors.newCachedThreadPool()


    1、PriorityBlockingQueue里面存储的对象必须是实现Comparable接口。

    2、队列通过这个接口的compare方法确定对象的优先级priority。

    规则是:当前和其他对象比较,如果compare方法返回负数,那么在队列里面的优先级就比较高

    下面的测试可以说明这个断言:

    查看打印结果,比较take出来的Entity和left的entity,比较他们的priority

    public class TestPriorityQueue { 
    
    static Random r=new Random(47); 
    
    public static void main(String args[]){ 
    
    final PriorityBlockingQueue q = new PriorityBlockingQueue(); 
    
    ExecutorService se = Executors.newCachedThreadPool(); 
    
    final int qTime = r.nextInt(100);
    //execute producer se.execute(new Runnable(){ public void run() { int i=0; while(true){ q.put(new PriorityEntity(r.nextInt(10), i++)); //优先级,索引 try { TimeUnit.MILLISECONDS.sleep(qTime); } catch (InterruptedException e) { e.printStackTrace(); } } } }); //execute consumer se.execute(new Runnable(){ public void run() { while(true){ try {
    int rTime = r.nextInt(500);

    //打印进队和出队的时间可以看到队列一直在累积 System.out.println(qTime + ": " rTime +
    " --take-- "+q.take()+" left: "+q.size()+" -- ["+q.toString()+"]"); try { TimeUnit.MILLISECONDS.sleep(rTime); } catch (InterruptedException e) { e.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); } } } }); //try { // TimeUnit.SECONDS.sleep(5); //} catch (InterruptedException e) { // e.printStackTrace(); //} System.out.println("shutdown"); } } class PriorityEntity implements Comparable<PriorityEntity> { private int priority; private int index=0; public PriorityEntity(int _priority,int _index) { this.priority = _priority; this.index=_index; } public String toString(){ return "# [index="+index+" priority="+priority+"]"; } //数字小,优先级高 public int compareTo(PriorityEntity o) { return this.priority > o.priority ? 1 : this.priority < o.priority ? -1 : 0; } //数字大,优先级高 // public int compareTo(PriorityTask o) { // return this.priority < o.priority ? 1 : this.priority > o.priority ? -1 : 0; // } }

    理解 newCachedThreadPool()

    1、创建线程池的根源:

    public ThreadPoolExecutor(int corePoolSize, 
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler)
    

    2、使用场景:
    2.1、耗时较短的任务。
    2.2、任务处理速度 > 任务提交速度 ,这样才能保证不会不断创建新的进程,避免内存被占满。newCachedThreadPool可以看成newFixedThreadPool(无穷大),虽然无法限制线程总数,但是可以减少不必要的线程创建和销毁上的消耗,

    3、取名为cached-threadpool的原因在于线程池中的线程是被线程池缓存了的,也就是说,线程没有任务要执行时,便处于空闲状态,处于空闲状态的线程并不会被立即销毁(会被缓存住),只有当空闲时间超出一段时间(默认为60s)后,线程池才会销毁该线程(相当于清除过时的缓存)。新任务到达后,线程池首先会让被缓存住的线程(空闲状态)去执行任务,如果没有可用线程(无空闲线程),便会创建新的线程。

    4、

    看一段测试代码:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class newCachedThreadPoolTest {
    public static void main(String[] args) {   ExecutorService executorService = Executors.newCachedThreadPool();   for (int i = 1; i < 10000; i++)   executorService.submit(new task());   }   }   class task implements Runnable {   @Override   public void run() {   try {   Thread.sleep(5000);   } catch (InterruptedException e) {   e.printStackTrace();     }   } }

    运行结果为:Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread


    可以看出来是堆外内存溢出,因为我们新建的线程都在工作(代码中用sleep表示在工作中),newCachedThreadPool 只会重用空闲并且可用的线程,所以上述代码只能不停地创建新线程,在 64-bit JDK 1.7 中 -Xss 默认是 1024k,也就是 1M,那就是需要 10000*1M = 10G 的堆外内存空间来给线程使用,但是我的机器总共就 8G 内存,不够创建新的线程,所以就 OOM 了。

    所以这个newCachedThreadPool 大家一般不用就是这样的原因,因为它的最大值是在初始化的时候设置为Integer.MAX_VALUE,一般来说机器都没那么大内存给它不断使用。当然知道可能出问题的点,就可以去重写一个方法限制一下这个最大值,但是出于后期维护原因,一般来说用 newFixedThreadPool 也就足够了。

    Java如何依据cpu核数设置合适的线程数

    newFixedThreadPool 定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()获取cpu核心数。

    executorservice pool = executors.newfixedthreadpool(runtime.getruntime().availableprocessors()*10);一般建议每cpu不超过25个线程,当然多一点也没什么问题,不过就费点线程资源.

    java.lang.Runtime.availableProcessors() 方法返回到Java虚拟机的可用的处理器数量。此值可能会改变在一个特定的虚拟机调用。应用程序可用处理器的数量是敏感的,因此偶尔查询该属性,并适当地调整自己的资源使用情况.

  • 相关阅读:
    left join 多表关联查询
    Dictionary解析json,里面的数组放进list,并绑定到DataGridView指定列
    C#同一位置切换显示两个Panel内容
    C#点击按钮用DataGridView动态增加行、删除行,增加按钮列
    C#获取本机mac地址
    C# MD5加密
    C# SQLiteDataReader获得数据库指定字段的值
    linux下mongodb安装、服务器、客户端、备份、账户命令
    ubuntu下创建python的虚拟环境
    python多进程之间的通信:消息队列Queue
  • 原文地址:https://www.cnblogs.com/xinxindiandeng/p/6378158.html
Copyright © 2011-2022 走看看