java笔记--使用线程池优化多线程编程

使用线程池优化多线程编程

认识线程池

在Java中,所有的对象都是需要通过new操作符来创建的,
如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下。
这种时候就需要用到了池的技术,比如数据库连接池,线程池等。

在java1.5之后,java自带了线程池,在util包下新增了concurrent包,
这个包主要作用就是介绍java线程和线程池如何使用的。

在包java.util.concurrent下的 Executors类中定义了Executor、ExecutorService、ScheduledExecutorService、
ThreadFactoryScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。

此类支持以下各种方法
    a.创建并返回设置有常用配置字符串的 ExecutorService 的方法。
    b.创建并返回设置有常用配置字符串的 ScheduledExecutorService 的方法。
    c.创建并返回“包装的”ExecutorService 方法,它通过使特定于实现的方法不可访问来禁用重新配置。
    d.创建并返回 ThreadFactory 的方法,它可将新创建的线程设置为已知的状态。
    e.创建并返回非闭包形式的 Callable 的方法,这样可将其用于需要 Callable 的执行方法中。
   --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897773.html "谢谢-- 
首先我们先来比较一下用线程池创建多个线程和用独立运行的方式创建多个线程的区别,
这里我们将通过比较两种方法占有内存和花费时间,来说明线程池的必要性重要性

代码实例:

package com.xhj.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 比较独立创建和线程池创建线程的优劣 比较因素--时间和占用内存
 *
 * @author XIEHEJUN
 *
 */
public class CompareThreadPool implements Runnable {
    private int id = 0;

    @Override
    public void run() {
        id++;

    }

    public static void main(String[] args) {
        /**
         * 独立创建1000个线程
         */
        {
            // 获取当前程序运行时对象
            Runtime run = Runtime.getRuntime();
            // 调用垃圾回收机制,以减少内存误差
            run.gc();
            // 获取当前JVM的空闲内存
            long freeMemory = run.freeMemory();
            // 系统当前时间
            long timePro = System.currentTimeMillis();
            // 独立创建并执行1000个线程
            for (int i = 0; i < 1000; i++) {
                new Thread(new CompareThreadPool()).start();
            }
            System.out.println("独立创建并执行1000个线程所需要占用的内存大小: "
                    + (freeMemory - run.freeMemory()));
            System.out.println("独立创建并运行1000个线程需要的时间为: "
                    + (System.currentTimeMillis() - timePro));
        }
        /**
         * 利用线程池创建1000个线程
         */
        {
            // 获取当前程序运行时对象
            Runtime run = Runtime.getRuntime();
            // 调用垃圾回收机制,以减少内存误差
            run.gc();
            // 获取当前JVM的空闲内存
            long freeMemory = run.freeMemory();
            // 系统当前时间
            long timePro = System.currentTimeMillis();
            ExecutorService service = Executors.newFixedThreadPool(2);
            // 独立创建并执行1000个线程
            for (int i = 0; i < 1000; i++) {
                service.submit(new CompareThreadPool());
            }

            System.out.println("使用线程池创建1000个线程所需要占用的内存大小: "
                    + (freeMemory - run.freeMemory()));
            // 线程池使用完成,关闭线程池
            service.shutdown();
            System.out.println("使用线程池创建并运行1000个线程需要的时间为: "
                    + (System.currentTimeMillis() - timePro));

        }

    }

}

结果为:

结论--为什么要用线程池:    
    通过上面这个例子,我们知道使用线程池可以大大的提高系统的性能,提高程序任务的执行效率,
    节约了系统的内存空间。在线程池中,每一个工作线程都可以被重复利用,可执行多个任务,
    减少了创建和销毁线程的次数。能够根据系统的承受能力,调整其线程数目,以便使系统达到运行的最佳效果。

线程池原理:
    一个线程池中有多个处于可运行状态的线程,当向线程池中添加Runnable或Callable接口对象时,
    就会有一个线程来执行run()方法或call()方法。如果方法执行完毕,则该线程并不终止,
    而是继续在池中处于可运行状态,以运行新的任务。

了解线程池(java中创建线程池的几种常用静态方法)

在java中,线程池的顶级接口是util.concurrent包下的Executors工具类,在这个类里,定义了很多操作线程池的方法。
其中最常用的线程池有:
1.创建单线程的线程池:
    newSingleThreadExecutor(),创建一个只有一个线程的线程池,此单线程按照任务的提交顺序执行所有的任务,
    若遇到异常中断,线程池则会重新建立一个单线程来替代其完成后续工作。
    
    代码实例:

    /**
     * 创建一个单线程的线程池
      *
     * @return
     */
    public ExecutorService SingleThreadPool() {
        ExecutorService singlePool = Executors.newSingleThreadExecutor();
        return singlePool;
    }

2.创建一个可缓存的线程池:
    newCachedThreadPool(),
创建一个不限制大小,且只能的线程池,他会根据任务量的多少来开辟和减少内存空间,
    但是线程池中线程的大小依赖于系统的性能或者JVM的容量
    
    代码实例:

   /**
     * 创建一个可缓存线程池
      *
     * @return
     */
    public ExecutorService CachedThreadPool() {
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        return cachedPool;
    }

3.创建一个大小固定的线程池:
    newFixedThreadPool(),
创建一个固定大小的线程池,任务提交则建立线程,直到线程大小达到线程池允许最大值,
    若某个线程结束,线程池则补充一个新的线程。

代码实例:

   /**
     * 创建一个大小固定的线程池
      *
     * @return
     */
    public ExecutorService FixedThreadPool() {
        ExecutorService fixedPool = Executors.newFixedThreadPool(2);
        return fixedPool;
    }

4.创建一个可定时、周期性执行的线程池
    newScheduledThreadPool(),
创建一个可定时、周期性执行的线程池,此线程池没有大小限制,
    实现周期性任务调度。

代码实例:

ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1);

为了便于大家理解和对比其不同之处,下面将把这几个常用线程池整合到一个程序当中,

代码实例:

package com.xhj.thread;

import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 几个常用线程池的理解与运用
 *
 * @author XIEHEJUN
 *
 */
public class CreateThreadPools extends Thread {

    @Override
    public void run() {
        System.out.println("系统时间 : " + System.currentTimeMillis() + " 线程: "
                + Thread.currentThread().getName() + "正在执行!!");

    }

    /**
     * 创建一个单线程的线程池
     *
     * @return
     */
    public ExecutorService SingleThreadPool() {
        ExecutorService singlePool = Executors.newSingleThreadExecutor();
        return singlePool;
    }

    /**
     * 创建一个大小固定的线程池
     *
     * @return
     */
    public ExecutorService FixedThreadPool() {
        ExecutorService fixedPool = Executors.newFixedThreadPool(3);
        return fixedPool;
    }

    /**
     * 创建一个可缓存线程池
     *
     * @return
     */
    public ExecutorService CachedThreadPool() {
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        return cachedPool;
    }

    /**
     * 将创建好的线程放入线程池,并执行
     *
     * @param pool
     */
    public void service(ExecutorService pool) {
        // 创建线程
        Thread thread1 = new CreateThreadPools();
        Thread thread2 = new CreateThreadPools();
        Thread thread3 = new CreateThreadPools();
        Thread thread4 = new CreateThreadPools();
        Thread thread5 = new CreateThreadPools();
        // 线程入线程池,并执行
        pool.execute(thread1);
        pool.execute(thread2);
        pool.execute(thread3);
        pool.execute(thread4);
        pool.execute(thread5);
        // 关闭线程池
        pool.shutdown();
    }

    /**
     * 创建一个大小无限制的线程池,可用与定时和周期性服务
     */
    public void scheduledThreadPool() {
        ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1);

        scheduledPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println("=======" + System.currentTimeMillis()
                        + "=========");
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);

        scheduledPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println(System.nanoTime());

            }
        }, 1000, 2000, TimeUnit.MILLISECONDS);

    }

    public static void main(String[] args) {
        CreateThreadPools creatThreadPool = new CreateThreadPools();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请选择创建线程池:1.单线程线程池;2.可缓存线程池;3.固定大小线程池;4可定时周期性执行线程池");
            int i = sc.nextInt();

            switch (i) {
            case 1:
                System.out.println("-----调用单线程的线程池-----");
                // 调用单线程的线程池
                creatThreadPool.service(creatThreadPool.SingleThreadPool());
                break;
            case 2:
                System.out.println("-----调用可缓存线程的线程池-----");
                // 调用可缓存线程的线程池
                creatThreadPool.service(creatThreadPool.CachedThreadPool());
                break;
            case 3:
                System.out.println("-----调用固定大小线程的线程池-----");
                // 调用固定大小线程的线程池
                creatThreadPool.service(creatThreadPool.FixedThreadPool());
                break;
            case 4:
                System.out.println("-----调用大小无限制可定时和周期性执行的线程池-----");
                // 调用固定大小线程的线程池
                creatThreadPool.scheduledThreadPool();
                break;
            }
        }
    }
}

注:当线程池任务结束之后,一定要记得将线程池关闭,执行shutdown()方法。

java笔记--使用线程池优化多线程编程,布布扣,bubuko.com

时间: 2024-10-07 08:19:34

java笔记--使用线程池优化多线程编程的相关文章

使用线程池优化多线程编程

Java中的对象是使用new操作符创建的,如果创建大量短生命周期的对象,这种方式性能非常低下.为了解决这个问题,而发明了池技术. 对于数据库连接有连接池,对于线程则有线程池. 本实例介绍两种方式创建1000个短生命周期的线程,第一种是普通方式,第二种是线程池的方式.通过时间和内存消耗的对比,就可以很明显地看出线程池的优势. 实例结果如下: 说明:使用线程池创建对象的时间是15毫秒,说明线程池是非常高效的. 关键技术: Executors类为java.util.concurrent包中所定义的Ex

Java 线程池和多线程编程 ——线程池理解与创建

JDK1.5 引入了 Executor框架 ,对任务提交和执行进行解耦 , 定义任务后交由线程池执行. 线程池是由java.util.concurrent 包中Executors类的工厂方法创建线程池. -------------------------------------------------------------------------------- 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程. public static ExecutorService n

Mysql线程池优化笔记

Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看. Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mysql thread pool,干什么用的?使用线程池主要可以达到以下两个目的:1.在大并发的时候,性能不会因为过载而迅速下降.2.减少性能抖动 thread pool的工作原理?线程池使用分而治之的方法来限制和平衡并发性.与默认的thread_handling不同,线程池将连接和线程划分开,所以连接数量和执

《Java并发编程的艺术》 第9章 Java中的线程池

第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 提高线程的可管理性.线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控. 9.1 线程池的实现原理 当提交一个新任务到线程池时,线程池的处理流程如下: 1)线程池判断核心线程池里的线程是否都在执行任务.如果不是,则创建

java笔记--关于线程通信

关于线程通信 使用多线程编程的一个重要原因就是线程间通信的代价比较小 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897773.html "谢谢-- 关键技术: yield(): Thread类的一个静态方法,用来暂停当前正在执行的线程对象,并执行其他线程 public static void yield(){} 代码实例: 实现线程间的发送和接收消息 package com.xhj.thread; /** * 线程之间的通信

java并发学习--线程池(一)

关于java中的线程池,我一开始觉得就是为了避免频繁的创建和销毁线程吧,先创建一定量的线程,然后再进行复用.但是要具体说一下如何做到的,自己又说不出一个一二三来了,这大概就是自己的学习习惯流于表面,不经常深入的结果吧.所以这里决定系统的学习一下线程池的相关知识. 自己稍微总结了一下,学习一些新的知识或者技术的时候,大概都可以分为这么几个点: 1.为什么会有这项技术,用原来的方法有什么问题. 2.这项新技术具体是怎么解决这个问题的(这时可能就要涉及到一些具体的知识点和编码了) 3.是不是使用这项技

【java基础】线程池

为什么要使用线程池 线程池用于多线程处理中,它可以根据系统的情况,可以有效控制线程执行的数量,优化运行效果.线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,那么超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行. 线程池的特点 线程复用 控制最大并发数量 管理线程 线程池的优点 降低资源消耗,通过重复利用已创建的线程来降低线程创建和销毁造成的消耗. 提高相应速度,当任务到达时,任务可以不需要的等到线程

Java中的线程池

综述 在我们的开发中经常会使用到多线程.例如在Android中,由于主线程的诸多限制,像网络请求等一些耗时的操作我们必须在子线程中运行.我们往往会通过new Thread来开启一个子线程,待子线程操作完成以后通过Handler切换到主线程中运行.这么以来我们无法管理我们所创建的子线程,并且无限制的创建子线程,它们相互之间竞争,很有可能由于占用过多资源而导致死机或者OOM.所以在Java中为我们提供了线程池来管理我们所创建的线程. 线程池的使用 采用线程池的好处 在这里我们首先来说一下采用线程池的

Java四种线程池的学习与总结

在Java开发中,有时遇到多线程的开发时,直接使用Thread操作,对程序的性能和维护上都是一个问题,使用Java提供的线程池来操作可以很好的解决问题. 一.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable(){ @Override public void run(){ //TODO Auto-generatedmethod stub } } ).start(); 那你就out太多了,new Thread的弊端如下: