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

认识线程池

在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笔记--使用线程池优化多线程编程的更多相关文章

  1. Java通过开启线程池实现多线程

    计算1..100  和1...200 的和,使用线程池开启两个线程 调用Executors类的newFixedThreadPool方法参数是线程池容纳的线程数量 这里是2 返回的对象是 Executo ...

  2. 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)

    数据结构(逻辑结构,物理结构,特点) 一.数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关.逻辑结构包括: 集合 数 ...

  3. Mysql线程池优化笔记

    Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看.     Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mys ...

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

    第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创 ...

  5. Java高并发 -- 线程池

    Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...

  6. 转载-SpringBoot结合线程池解决多线程问题实录;以及自己的总结

    原文地址:https://blog.csdn.net/GFJ0814/article/details/92422245 看看这篇文章(继续学习):https://www.jianshu.com/p/3 ...

  7. Java中的线程池用过吧?来说说你是怎么理解线程池吧?

    前言 Java中的线程池用过吧?来说说你是怎么使用线程池的?这句话在面试过程中遇到过好几次了.我甚至这次标题都想写成[Java八股文之线程池],但是有点太俗套了.虽然,线程池是一个已经被说烂的知识点了 ...

  8. JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析

    JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...

  9. java笔记--关于线程通信

    关于线程通信 使用多线程编程的一个重要原因就是线程间通信的代价比较小 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897773.h ...

随机推荐

  1. iOS 自定义控件开发(上)

    工作需要,最近在进行iOS方面的图表工作.找了很多第三方库都无法实现效果,所以决定自己写一个控件. <iOS 自定义控件开发(上)> <iOS 自定义控件开发(中)> #0 目 ...

  2. jdbc基础 (四) 批处理

    批处理,就是字面上的意思,一次性处理一批sql语句. 直接看例子吧: package com.cream.ice.jdbc; import java.sql.Connection; import ja ...

  3. VC6.0读取Excel文件数据

    啰嗦一下:本人所在公司从事碟式斯特林太阳能发电设备的研发与销售.单台设备图如下: 工作原理如下:整个设备大致可分为五个部分, 1.服务器,负责气象.发电等数据存取,电.网连接等处理: 2.气象站,通过 ...

  4. .net,微软,薪资及其他

    很久没在博客园上写些东西,因为我的确没有什么技术上面新奇的心得和大家分享,园子里面的文章页没啥看的,基本就是看一下业界新闻,因为这里面99%的东西没什么看头,更像是个人技术笔记汇总. 我从07年从de ...

  5. 20.C#LINQ基础和简单使用(十一章11.1-11.2)

    终于看到了第11章,之前虽然也有看过,但没有太仔细,在工作中也偶尔会使用,但不明白其中的原理,那现在就来讲讲LINQ,做一做书虫~~ 首先先了解下LINQ的三个要点: LINQ不能把非常复杂的查询表达 ...

  6. 关于1Byte 1K 1M 1G(换算)

    1个字节等于8位二进制 .... 1byte=8bit 1K = 1024 byte =1024byte*8b 说白一点就是 1M等于1024个K组成,而1K又等于1024B,所以1M等于1024K乘 ...

  7. DOM(二)使用DOM

    在了解DOM(文本对象模型)的框架和节点后,最重要的是使用这些节点处理html网页 对于一个DOM节点node,都有一系列的属性和方法可以使用.常用的有下表. 完善:http://www.w3scho ...

  8. Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs

    目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use ...

  9. Tomcat 在win7/win8 系统下tomcat-users.xml.new(拒绝访问)解决方法

    tomcat启动报错No UserDatabase component found under key UserDatabase 也可以这样处理 Tomcat 在win7/win8 系统下tomcat ...

  10. 学习笔记--博弈组合-SG函数

    fye学姐的测试唯一的水题.... SG函数是一种游戏图每个节点的评估函数 具体定义为: mex(minimal excludant)是定义在整数集合上的操作.它的自变量是任意整数集合,函数值是不属于 ...