1. 场景描述

以前多线程也常用,这次因需再页面上用到多线程,如下图,总结下,有需要的朋友可以参考下。

2. 解决方案

2.1 线程池概念

线程池官方定义不说了,通俗说下:池子的概念,事先(预定义)创建后,后续的线程可以直接从池子中拿,好处:

(1)来创建线程比较消耗资源,不用重复创建;

(2)池子事先定义好,避免无节制创建线程,导致系统出现不可预测风险。

2.2 创建方式

采用jdk自带的线程池创建方式,jdk1.5开始提供,在java.util.concurrent 的包下面。

表面上有两种创建方式,其实一种。

(1)一种是采用new ThreadPoolExecutor进行创建;

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

(2)一种是采用Executors.newFixedThreadPool(3),不过还是调用的new ThreadPoolExecutor进行的线程池创建,赋值了几个默认参数而已。

new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());

2.3 参数含义

一共有 7 个参数:

(1)corePoolSize

核心线程数,当有任务进来的时候,如果当前线程数还未达到 corePoolSize 个数,则创建核心线程,核心线程有几个特点:

1、当线程数未达到核心线程最大值的时候,新任务进来,即使有空闲线程,也不会复用,仍然新建核心线程;2、核心线程一般不会被销毁,即使是空闲的状态,但是如果通过方法 allowCoreThreadTimeOut(boolean value) 设置为 true 时,超时也同样会被销毁;3、生产环境首次初始化的时候,可以调用 prestartCoreThread() 方法来预先创建所有核心线程,避免第一次调用缓慢;

(2)maximumPoolSize

除了有核心线程外,有些策略是当核心线程完全无空闲的时候,还会创建一些临时的线程来处理任务,maximumPoolSize 就是核心线程 + 临时线程的最大上限。临时线程有一个超时机制,超过了设置的空闲时间没有事儿干,就会被销毁。

(3)keepAliveTime

这个就是上面两个参数里所提到的超时时间,也就是线程的最大空闲时间,默认用于非核心线程,通过 allowCoreThreadTimeOut(boolean value) 方法设置后,也会用于核心线程。

(4)unit

这个参数配合上面的 keepAliveTime ,指定超时的时间单位,秒、分、时等。

(5)workQueue

等待执行的任务队列,如果核心线程没有空闲的了,新来的任务就会被放到这个等待队列中。

(6)threadFactory

它是一个接口,用于实现生成线程的方式、定义线程名格式、是否后台执行等等,可以用 Executors.defaultThreadFactory() 默认的实现即可,也可以用 Guava 等三方库提供的方法实现,如果有特殊要求的话可以自己定义。它最重要的地方应该就是定义线程名称的格式,便于排查问题了吧。

(7)handler

当没有空闲的线程处理任务,并且等待队列已满(当然这只对有界队列有效),再有新任务进来的话,就要做一些取舍了,而这个参数就是指定取舍策略的,有下面四种策略可以选择:

ThreadPoolExecutor.AbortPolicy:直接抛出异常,这是默认策略;

ThreadPoolExecutor.DiscardPolicy:直接丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后将新来的任务加入等待队列

ThreadPoolExecutor.CallerRunsPolicy:由线程池所在的线程处理该任务,比如在 main 函数中创建线程池,如果执行此策略,将有 main 线程来执行该任务

2.4 测试验证

2.4.1 测试线程
package com.yutong.laowang.test;

public class ThreadTest extends Thread{
@Override
public void run() {
System.out.println("软件老王:" +Thread.currentThread().getName());
}
}
2.4.2 Executors创建
  private static void test4() {
Executor mExecutor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
Thread thread = new ThreadTest();
mExecutor.execute(thread);
}
}

结果:

软件老王:pool-2-thread-2
软件老王:pool-2-thread-3
软件老王:pool-2-thread-1
软件老王:pool-2-thread-3
软件老王:pool-2-thread-2
软件老王:pool-2-thread-1
软件老王:pool-2-thread-3
软件老王:pool-2-thread-2
软件老王:pool-2-thread-3
软件老王:pool-2-thread-1
2.4.3 ThreadPoolExecutor创建
 private static void test3() {
int poolSize = 5;
int queueSize = 100;
ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(queueSize), new ThreadPoolExecutor.AbortPolicy()); for (int i=0;i<10;i++) {
executorService.submit(new ThreadTest());
}
}

结果:

软件老王:pool-2-thread-1
软件老王:pool-2-thread-3
软件老王:pool-2-thread-4
软件老王:pool-2-thread-2
软件老王:pool-2-thread-5
软件老王:pool-2-thread-5
软件老王:pool-2-thread-1
软件老王:pool-2-thread-2
软件老王:pool-2-thread-2
软件老王:pool-2-thread-1
2.4.4 线程停用
thread.interrupt();
---有时候不一定能执行成功,一般会结合判断使用,软件老王,例如:
在ThreadTest类中进行判断,默认为false,当满足条件下为true,停用线程。
public volatile boolean exit = false;

I’m 「软件老王」,如果觉得还可以的话,关注下呗,后续更新秒知!欢迎讨论区、同名公众号留言交流!

java多线程与线程池的更多相关文章

  1. Java多线程与线程池技术

    一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...

  2. Java 多线程:线程池

    Java 多线程:线程池 作者:Grey 原文地址: 博客园:Java 多线程:线程池 CSDN:Java 多线程:线程池 工作原理 线程池内部是通过队列结合线程实现的,当我们利用线程池执行任务时: ...

  3. java多线程、线程池及Spring配置线程池详解

    1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源.2.java中简单的实现多线程的方式 继承Thread ...

  4. Java多线程和线程池

    转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...

  5. Java多线程之线程池详解

    前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...

  6. JAVA多线程(三) 线程池和锁的深度化

    github演示代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-servic ...

  7. Java多线程-ThreadPool线程池(三)

    开完一趟车完整的过程是启动.行驶和停车,但老司机都知道,真正费油的不是行驶,而是长时间的怠速.频繁地踩刹车等动作.因为在速度切换的过程中,发送机要多做一些工作,当然就要多费一些油. 而一个Java线程 ...

  8. java 多线程 4 线程池

    系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...

  9. Java多线程之线程池

    现在是多核的时代,面向多核的编程很重要,因此基于java的并发和多线程开发非常重要. 线程池是于队列密切相关的,其中队列保存了所有等待执行的任务.工作者线程的任务很简单:从队列中获取一个任务,执行任务 ...

  10. Java多线程(四) 线程池

    一个优秀的软件不会随意的创建.销毁线程,因为创建和销毁线程需要耗费大量的CPU时间以及需要和内存做出大量的交互.因此JDK5提出了使用线程池,让程序员把更多的精力放在业务逻辑上面,弱化对线程的开闭管理 ...

随机推荐

  1. 【Java必修课】String.intern()原来还能这么用(原理与应用)

    1 简介 String.intern()是JDK一早就提供的native方法,不由Java实现,而是底层JVM实现,这让我们对它的窥探提高了难度.特别是在Oracle收购了Sun公司后,源代码不开源了 ...

  2. Matplotlib 中常见的图形

    # 导包 from matplotlib import pyplot as plt import numpy as np 线性图 简单线性图 在图表的所有类型中,线性图最为简单.线性图的各个数据点由一 ...

  3. 爬虫之selenium爬取京东商品信息

    import json import time from selenium import webdriver """ 发送请求 1.1生成driver对象 2.1窗口最大 ...

  4. 在线热备份数据库之innobackupex 增量备份InnoDB

    在线热备份数据库之innobackupex 增量备份InnoDB 什么是增量备份?其原理是什么? 增量备份是基于上一次备份后对新增加的内容进行备份,优点相较于完整备份而言备份内容少时间短,能够节省磁盘 ...

  5. ubuntu16安装docker环境详细说明

    安装前说明: 本文将介绍在ubuntu16.04系统下安装和升级docker.docker-compose.docker-machine. docker:有两个版本:docker-ce(社区版)和do ...

  6. mysql-清除binlog日志命令

    记录一个清除MySQL里binlog日志的命令,可用在定时任务脚本里. 只保留1天前的日志: PURGE MASTER LOGS BEFORE DATE_SUB(CURRENT_DATE, INTER ...

  7. 文件输入输出函数fgetc/fputc及fgets/fputs等文件指针位置的变化

    文件打开后才可以对文件进行操作.也就是说,文件必须经历打开-操作-关闭的过程.如前所述,C语言对文件的操作都是通过调用标准I/O库函数来实现的.文件操作实际是指对文件的读写.文件的读操作就是从文件中读 ...

  8. JavaScript with Image:创建缩略图

    当图片很大,直接把图片从Server下载到浏览器上看是一种很不明智的做法,浪费了服务器的资源,网络带宽和客户端的资源.所以,通常Server和Client之间会传输缩略图,只有当Client请求某张图 ...

  9. PHP Laravel5实现的RBAC权限管理操作示例

    根据不同的权限,在菜单栏显示不同的功能,只对菜单进行了限制,若对路由也进行限制,可以根据菜单的例子,请自行完善,开发.下面请认真学习一下laravel的RBAC设计 1.建表(用户表.角色表.权限表. ...

  10. iOS:应用程序扩展开发之Today扩展(Today Extesnsion)

    一.简介 iOS应用程序扩展是苹果在iOS8推出的一个新特性,可以将自定义的功能和内容扩展到应用程序之外,在之后又经过不断地优化和更新,已经成为开发中不可或缺的功能之一.扩展也是一个Target项目, ...