线程池是多线程的处理形式,在处理的过程中将任务添加到队列中,然后在创建线程后启动这些任务。线程池会维护这多条线程,等待监督管理者分配并发执行的任务。线程池不仅要能够保证内核的充分利用,还能防止过度调用。
Java内嵌线程池,
为什么要用线程池
优点
缺点
线程池应用哪些场景
企业场景
只要有并发的地方,任务数据或大或小,时间或长或短都可以使用线程池;
/**
* corePoolSize 线程池中的线程数
* maximumPoolSize 线程池允许的最大线程数
* keepAliveTime 当线程数量大于核心时,这是剩余空闲线程在终止前等待新任务的最大时间
* unit 时间单位
* workQueue 在执行任务之前用来保存任务的队列
**/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* threadFactory 创建多线程时使用的工厂
**/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**
* handler 当执行因线程边界和队列容量达到而被阻塞时使用的处理程序
**/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
核心线程数(corePoolSize)
最大线程数(maximumPoolSize)
最大空闲时间(keepAliveTime)
任务队列长度(workQueue)
时间单位(unit)
线程工厂(ThreadFactory)
拒绝策略(handler)

1,编写任务类(MyTask),实现Runnable接口,
package com.sin.demo;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 任务类
* 需求:
* 自定义线程联系,要实现Runnable接口
* 包含任务编号,每个任务执行时间设计为0.2秒
*/
public class MyTask implements Runnable{
private int id;
public MyTask(int id) {
this.id = id;
}
@Override
public void run() {
String name =Thread.currentThread().getName();
System.out.println("线程:"+name+"即将执行任务:"+id);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+name+"完成任务:"+id);
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
2,编写线程类(MyWorker),用于执行任务,需要持有所有任务
package com.sin.demo;
import java.util.List;
/**
* 线程类,
* 需求:
* 需要继承Thread类,设计一个属性,用于保存线程的名字
* 设计一个集合,用于保存所有的任务。
*/
public class MyWorker extends Thread{
//用来保存线程的名字
private String name;
private List tashs;
//利用有参构造方法,给成员变量赋值
public MyWorker(String name,List tashs){
super(name);
this.tashs = tashs;
}
@Override
public void run() {
//判断集合中是否有任务,只要时有,那就之一执行下去
while(tashs.size()>0){
Runnable runnable = tashs.remove(0);
runnable.run();
}
}
}
3,编写线程池类(MyThreadPool),包括提交任务,执行任务的能力,
package com.sin.demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* 线程池类
* 成员变量:
* 1,任务队列, 集合, 控制线程安全问题
* 2,当前线程数量
* 3,核心线程数量
* 4,最大线程数量
* 5,任务队列的长度
* 成员方法:
* 1,提交任务:
* 将任务添加到集合中,需要判断是否超出了任务的总长度
* 2,执行任务:
* 判断当前线程的数量,决定创建核心线程还是非核心线程
*/
public class MyThreadPool {
//成员变量:
//1,任务队列
private List tasks = Collections.synchronizedList(new ArrayList());
//2,当前线程数量
private int num;
//3,核心线程数量
private int corePoolSize;
//4,最大线程数量
private int maxSize;
//5,任务队列的长度
private int workSize;
public MyThreadPool( int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
//成员方法:
//1,提交任务
public void submit(Runnable runnable){
//判断当前集合中任务的数量,是否超出了最大任务数
if (tasks.size()>=workSize){
System.out.println("该任务:"+runnable+"被丢弃掉了");
}else {
tasks.add(runnable);
//执行任务
execTask(runnable);
}
}
//2,执行任务
public void execTask(Runnable runnable){
//判断当前线程池的线程总数量,是否超出了核心数
if (num 4,编写测试类(MyTest),创建线程对象,提交多个任务测试。
package com.sin.demo;
/**
* 测试类:
* 1,创建线程池类对象;
* 2,提交多个任务;
*/
public class MyTest {
public static void main(String[] args) {
//1,创建线程池类对象(corepoolSize:核心线程数量,mixSize:最大线程数,workSize:任务队列的长度)
MyThreadPool pool = new MyThreadPool(2,4,20);
//2,提交多个任务
for (int i=0;i<30;i++){
//创建任务对象,并提交给线程池
MyTask myTask = new MyTask(i);
pool.submit(myTask);
}
}
}
ExecutorService获取
获取ExecutorService可以利用jdk中的Executors类中的静态方法
newCachedThreadPool
package com.sin.demo;
/**
* 任务类,包含一个任务编号,在任务中,打印出是哪一个线程正在执行任务
*/
public class MyRunnable implements Runnable {
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
//获取线程的名称,
String name =Thread.currentThread().getName();
System.out.println("ThreadName--:"+name+"runningID--:"+id);
}
}
package com.sin.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* 练习Executor获取ExecutorService,然后调用方法,提交任务。
*/
public class MyTest02 {
public static void main(String[] args) {
//test1();
test2();
}
private static void test1(){
//使用工厂类获取线程对象
ExecutorService executorService = Executors.newCachedThreadPool();
//提交任务
for(int i=1;i<=10;i++){
executorService.submit(new MyRunnable(i));
}
}
private static void test2(){
//使用工厂类获取线程池对象
ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
int n = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"SetThreadName:"+n++);
}
});
//提交任务
for (int i=1;i<=10;i++){
executorService.submit(new MyRunnable(i));
}
}
}
newFixeThreadPool
package com.sin.demo;
/**
* 任务类,包含了一个任务编号,在任务中,打印出一是那个一个线程正在执行任务
*/
public class MyRunnable2 implements Runnable{
private int id;
public MyRunnable2(int id) {
this.id = id;
}
@Override
public void run() {
//获取线程的名称,打印出来
String name = Thread.currentThread().getName();
System.out.println("ThreadName----->:"+name+"runningId----->:"+id);
}
}
package com.sin.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* 测试类
*/
public class MyTest03 {
public static void main(String[] args) {
//test1();
test2();
}
private static void test1(){
//使用工厂类获取线程对象
ExecutorService executorService = Executors.newFixedThreadPool(3);
//提交任务
for (int i=1;i<=10;i++){
executorService.submit(new MyRunnable2(i));
}
}
private static void test2(){
//使用工厂类获取线程池对象
ExecutorService executorService = Executors.newFixedThreadPool(3, new ThreadFactory() {
int n = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"setThreadName---->"+n++);
}
});
//提交任务
for (int i=1;i<=10;i++){
executorService.submit(new MyRunnable2(i));
}
}
}
案例介绍:
我看某个商场退出了秒杀活动,上10部爱疯13免费送给参与直播间里的客户,
要求:
1,使用线程池来创建线程
2,解决线程安全问题。
思路:
1,既然商品数量为10个,那么我们就可以创建线程池的时候将初始显示书来给你为10或者以下,设计线程池最大数量10;
2,当某个线程执行任务只好,可以让其他秒杀的人继续是用该线程参与秒杀;
3,使用synchronized控制线程安全,防止出现错误数据。
代码流程:
1,编写任务类,主要是送出手机给秒杀成功的客户;
2,编写主程序类,创建20个任务(20个客户参与);
3,创建线程池对象并且接收出这20个,开始执行20.
任务类
package com.sin.demo;
/**
* 任务类:
* 包含了商品数量,客户名称,送出爱疯的行为。
*/
public class MyTask implements Runnable{
//设计一个变量,爱疯13的数量
private static int id=10;
//设计一个客户名称
private String userName;
public MyTask(String userName) {
this.userName = userName;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(userName+"user:ing"+name+"miaosha:ing");
try{
Thread.sleep(200);
}catch (Exception e){
e.printStackTrace();
}
synchronized (MyTask.class){
if(id>0){
System.out.println(userName+"use--->"+name+"miaosha---->"+id--+"id,success");
}else {
System.out.println(userName+"use--->"+name+"shibei");
}
}
}
}
主线程类
package com.sin.demo;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 主线程列,测试任务类
*/
public class MyTest05 {
public static void main(String[] args) {
//1,创建一个线程池对象
ThreadPoolExecutor executor = new ThreadPoolExecutor(3,5,1, TimeUnit.MINUTES,
new LinkedBlockingDeque<>(15));
//2,循环创建任务对象
for(int i=1;i<=20;i++){
MyTask myTask = new MyTask("userName"+i);
executor.submit(myTask);
}
//3,关闭线程池
executor.shutdown();
}
}