Java 进阶7 并行优化 JDK多任务执行框架技术 20131114
         Java 语言本身就是支持多线程机制的,他提供了 Thread 类 Runnable 接口等简单的多线程支持工具,同时为了进一步改善并发程序的性能,在 JDK中还提供了用于多线程管理的线程池概念。并行优化中,一个重要的知识点就是 线程池技术
ExecutorService exe = Executors.newCachedThreadPool();
1. 无限制线程的缺陷
          多线程设计的软件方法确实可以最大限度的发挥现代多核处理器的计算能力,提高生产系统的吞吐量和性能。但是如果不加控制的随意的使用多线程技术,对于系统性能反而会产生不利的影响,线程的创建,线程上下文的切换需要消耗十分大的系统资源,当线程的数量过多的时候,就会造成很大的系统开销,导致程序的性能降低。
          当我们创建一个线程并且执行完毕的时候, JVM会自动回收线程的资源。在简单的系统中是没有问题的,但是实际的生产过程中,因为实际环境的需要,可能会开启很多的线程资源来支撑业务的需要,这样的话,因为线程数量过大,就会好近 CPU资源,而且忙于线程的切换。虽然线程相比进程轻量级一些,但是线程的创建和回收依然需要花费时间;同时线程资源的创建也是会占用内存空间的,大量的线程会抢占大量的内存资源,如果处理不当的话,会出现内存溢出的情况,导致程序终止,同时大量的线程回收会给GC机制带来很大的负担。
          所以说实际生产的过程中,线程的数量是必须控制的。盲目的大量创建线程的话,对于系统性能影响非常大。
2. 简单线程池的实现
          为了节省系统资源在多线程并发的时候不断的创建和销毁线程的额外开销,就引入了线程池的概念。线程池的基本功能就是线程的复用。当系统接收到一个任务的时候,需要一个线程的时候,不是去创建线程,而是去线程池中查找是否有空闲的线程资源,如果有的话,就会直接使用线程池中的线程执行任务,如果没有的话,才会去创建线程。等待任务完成之后,不是简单的销毁线程资源,而是将现场放入到线程池中空闲队列中,等待下次再次使用。
3.Executor 框架
         JDK 中对于多线程提供一套 Executor框架,帮助开发人员有效的进行线程控制。这些 Class在包 java.util.concurrrent 包中,是 JDK并发包的核心类。其中ThreadPool Executor表示一个线程池。 Executors扮演者线程池工厂的角色,通过 Executors可以取得一个特定功能的线程池。
         Executor : execute
         ExecutorService: shutdown     isShutdown       isTerminated   submit
         AbstractExecutorService:
         ThreadPoolExecutor
         Executors:
ExecutorService exe = Executors.newCachedThreadPool();
for(int I = 0; i< 100; i++){
         exe.submit(new Mythread());
}
这一段代码完成了 100次调度,和前面的线程池差不多;
和简单的线程池相比, Executor框架提供了更多有用的功能。 Executors工厂类提供的主要方法:
public static ExecutorService newFixedThreadPool(in nThreads);
创建固定数量线程的线程池,该线程池中的线程数量始终不会变化。当有一个新的任务提交到线程池中,如果有空闲的线程的话,就会立即执行,否则,新的任务将会被暂存在一个任务队列中,带线程空闲的的时候,便会处理在任务队列中的任务。
public static ExecutorService newSingleThreadExecutor();
该方法创建的线程池中仅仅有一个线程,当超过一个任务被提交到线程池中,那么任务会保存在任务队列中,按照队列的顺序执行任务
public static ExecutorService newCachedThreadPool()
返回一个根据实际情况调整线程数量的线程池。线程池中线程的数量是不确定的,如果有空闲的线程可以使用的话,就会优先使用可以复用的线程,如果没有的话,就会创建新的线程处理任务,所有线程执行完毕之后,不是直接销毁线程,而是返回到线程池中。
public static ScheduledExecutorExecutor newSingleThreadScheduledExecutor():
返回一个 ScheduledExecutorService,线程池的大小事1, ScheduleExecutorService继承自ExecutorService ,扩展了在给定时间内执行某任务的功能,如在某个固定的时间延迟之后执行或者是周期性的执行某些任务,函数原型是:
         schedule(Runnable command, long delay, TimeUnit);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
相对上一个线程池,就是线程池中的线程的数量是可以自己定义的。
4. 自定义线程池
          其实以上的线程池方法,在底层都是使用的 ThreadPoolExecutor实现的,都是针对ThreadPoolExecutor实现的封装, ThreadPoolExecutor拥有一个强大的封装机制:
public ThreadPoolExecutor(
         int corePoolSize,// 指定线程池中线程的数量
         int maximunPoolSize,// 指定线程池中线程的最大数量
long keepAliveTime,//当线程池线程数量超过corePoolSize时,多余的空闲线程的存活时间
TimeUnit unit, //keepAliveTime参数的单位
BlockingQueue<Runnable> workQueue,// 任务队列,被提交的但是尚未被处理的任务
ThreadFactory threadFactory,//线程工厂,用于创建线程
RejectedExecutionHandler handler);//拒绝策略,当线程池中有太多的任务请求的时候,如何拒绝任务。
JDK中是内置了拒绝策略的:
         AbortPolicy 策略:该策略会直接抛出异常,组织系统长长运行;
         CallerRunsPolicy 策略:只要线程池没有关闭,该策略直接在调用者线程中,运行当前被丢弃的任务;
         DiscardOledestPolicy: 丢弃最老的一个请求,也就是即将被执行的第一个任务,并且尝试再次提交任务;
         DiscardPolicy: 默默的丢弃无法处理的任务,不予任何的理睬。
          以上的策略都是实现了 RejectedExecutionHandler接口,如果依旧是没有满足你的需要的话,那么可以自己定义类实现 RejectedExecutionHandler接口。
public static void main(String[] args) {
        ExecutorService exe = new ThreadPoolExecutor(
                100,
                200,
                0L,
                TimeUnit. SECONDS,
                 new LinkedBlockingQueue<Runnable>());
         for(int i = 0 ;i<1000;i++){
            exe.execute( new Thread("" +i+"" ){
                 public void run(){
                     try {
                        Thread. sleep(100);
                    } catch (InterruptedException e) {
                         // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System. out.println("thread" + this.getName());
                }
            });
        }
    }
}
对于队列的话,可以使用的队列的种类有:
直接提交的队列:使用 SynchronizedQueue实现的,他是没有容量的,而且同步机制会大大降低程序的运行效率,一般不推荐使用;
有界任务队列:使用的是 ArrayBlockingQueue实现的
无界任务队列:使用的是 LinkedBlockingQueue类实现的,除非系统资源好近,否则不会存在任务添加失败的情况。
优先任务队列:使用的是 PriorityBlockingQueue实现的,会根据任务的优先级进行排序,因为这样就会出现比较,所以我们需要对线程实现 Comparable<CompareType>接口中的public int compareTo(CompareType o)方法,才可以使用优先任务队列。
     当内置的线程池无法满足你的需要的时候,就可以考虑自定义线程池
5优化线程池的大小
     线程池的大小对于系统的性能也有十分重要的影响,线程的数量过大或者过小的话,都无法发挥最优的性能,但是线程池的大小也没有必要做的十分精确,只要避免线程数量极大或者是极小的情况既可以了,这样对于系统性能的影响不会很大。线程池容量的大小需要考虑的因素有:CPU 的数量,内存大小, JDBc连接状况等等
     计算公式:
    NThread = Ncpu * Ucpu * (1+ W/C)
其中 Ncpu值得是 CPU的数量,可以使用 Runtime.getRuntime().availableProcessors() 获得计算机中的 CPU数量;
Ucpu指的是目标CPU 的使用率;
W/C: 等待时间和计算时间的比值。
6.扩展线程池ThreadPoolExecutor
    ThreadPoolExecutor 他是一个可以扩展的线程池,提供了 beforeExecute afterExecute, terminated()三个接口对线程池进行控制。
 
Tengfei Yang
于广州中山大学 图书馆
20131114

Java 进阶7 并行优化 JDK多任务执行框架技术的更多相关文章

  1. JDK多任务执行框架(Executor框架)

    Executor的常用方法 为了更好的控制多线程,JDK提供了一套线程框架Executor,帮助开发人员有效地进行线程控制.它们都在java.util.concurrent包中,是JDK开发包的核心. ...

  2. Java进阶7并发优化4——JDK并发数据结构

    Java进阶7并发优化4——JDK并发数据结构20131114 由于并发程序和串行程序的不同特点,在串行程序中使用的数据结构可能无法在并行程序中直接的正常使用,因为这些数据结构可能不是线程安全的,所以 ...

  3. Java进阶7 并发优化2 并行程序设计模式

    Java进阶7 并发优化2 并行程序设计模式20131114 1.Master-worker模式 前面讲解了Future模式,并且使用了简单的FutureTask来实现并发中的Future模式.下面介 ...

  4. Java 进阶7 并发优化 5 并发控制板方法

    Java 进阶7 并发优化 5 并发控制板方法 20131114 前言:          Java 中多线程并发程序中存在线程安全的问题,之前学习 Java的同步机制,掌握的同步方法只有一种就是使用 ...

  5. Java 进阶7 并发优化 1 并行程序的设计模式

       本章重点介绍的是基于 Java并行程序开发以及优化的方法,对于多核的 CPU,传统的串行程序已经很好的发回了 CPU性能,此时如果想进一步提高程序的性能,就应该使用多线程并行的方式挖掘 CPU的 ...

  6. JavaJDK多任务执行框架(六)

    class Temp extends Thread { public void run() { System.out.println("run"); } } public clas ...

  7. Java线程间通信方式剖析——Java进阶(四)

    原创文章,同步发自作者个人博客,转载请在文章开头处以超链接注明出处 http://www.jasongj.com/java/thread_communication/ CountDownLatch C ...

  8. 从ConcurrentHashMap的演进看Java多线程核心技术 Java进阶(六)

    本文分析了HashMap的实现原理,以及resize可能引起死循环和Fast-fail等线程不安全行为.同时结合源码从数据结构,寻址方式,同步方式,计算size等角度分析了JDK 1.7和JDK 1. ...

  9. Java多线程--锁的优化

    Java多线程--锁的优化 提高锁的性能 减少锁的持有时间 一个线程如果持有锁太长时间,其他线程就必须等待相应的时间,如果有多个线程都在等待该资源,整体性能必然下降.所有有必要减少单个线程持有锁的时间 ...

随机推荐

  1. SqlHelper简单实现(通过Expression和反射)9.Sql表述对象SqlSession

    此类是整个SqlHelper的另一个核心,基本思想就是通过EntityHelper,ObjectHelper和ExpressionHelper获取拼接Select语句的全部元素,拼接出完整Select ...

  2. JAVA中UDP使用

    UDP协议 在有些应用程序中,保持最快的速度比保证每一位数据都正确到达更重要.例如,在实时音频或视频中,丢失数据包只会作为干扰出现.干扰是可以容忍的,但当TCP请求重传或等待数据包到达而它却迟迟不到时 ...

  3. 十八般武艺之 Runloop

    嗯,runloop ,看过,用过.但是有时候突然被问到,总是不能很好的描述给他人,也许是程序员本来口拙的缘故吧.另外,也是对runloop还是理解的不够透彻. 于是乎,决定重新整理一下,加深一下印象. ...

  4. 在父页面和其iframe之间函数回调 父页面回调iframe里写的函数

    // @shaoyang  父页面 window['mengBanLogin']={ mengBanArr : new Array(), mengBanLoginSuccess : function( ...

  5. fastdfs安装与配置

    FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服务,如相 ...

  6. 20145321 《Java程序设计》第4周学习总结

    20145321 <Java程序设计>第4周学习总结 教材学习内容总结 第六章 继承与多态 6.1 何谓继承 1.继承共同行为: 继承基本上就是避免多个类间重复定义的行为. Pull Up ...

  7. 20145333 《Java程序设计》第5周学习总结

    20145333 <Java程序设计>第5周学习总结 教材学习内容总结 语法与继承架构 使用try.catch Java中所有错误都会被包装成对象,可以尝试(try)执行程序并捕捉(cat ...

  8. 20145240《网络对抗》MSF基础应用

    MSF基础应用 一个主动攻击,如ms08_067 启动msf search ms08_067,查找相应的漏洞,查询可攻击的模块. 根据上述漏洞的模块use exploit/windows/smb/ms ...

  9. 关于js中对事件绑定与普通事件的理解

    普通事件指的是可以用来注册的事件: 事件绑定是指把事件注册到具体的元素之上. 通俗点说: 普通事件:给html元素添加一个特定的属性(如:onclick): 事件绑定:js代码中通过标记(id  ta ...

  10. Oracle查询一个表的数据插入到另一个表

    1. 新增一个表,通过另一个表的结构和数据 create table XTHAME.tab1 as select * from DSKNOW.COMBDVERSION 2. 如果表存在: insert ...