刚要
- 理解线程池基本概念
- 理解线程池工作原理
- 【掌握】自定义线程池
- 【应用】java内置线程池
- 【应用】使用java内置线程池完成综合案例
1. 线程池基本概念
2. 线程池使用
2.1 java内置线程池
我们想要自定义线程池,必须先了解线程池的工作原理,才能自己定义线程池;通过java中ThreadPoolExecutor的源码来学习:
java.util.ThreadPoolExecutor类 jdk1.5
该类继承了AbstractExecutorService,而AbstractExecutorService实现了Executor这个接口。
3. 自定义线程池
/*
自定义线程池练习:任务类,需要实现Runnable接口;
包含任务编号,每一个任务执行时间设计为 0.2秒
*/
public class MyTask implements Runnable{
private int id;//任务编号
//由于run方法是重写接口中的方法,因此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);
}
}
import java.util.List;
/*
编写一个线程类,需要继承Thread类;设计一个属性,用于保存线程的名字;
设计一个集合,用于保存所有的任务;
*/
public class MyWorker extends Thread{
private String name;//保存线程的名字
private List<Runnable> tasks;//所有的任务集合
//利用构造方法给成员变量赋值
public MyWorker(String name, List<Runnable> tasks){
super(name);//
this.tasks = tasks;
}
@Override
public void run(){
//判断集合中是否有任务,只要有,就一直执行
while (tasks.size() > 0){
Runnable r = tasks.remove(0);//取出当前任务
r.run();
}
}
}
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/*
自定义的线程池类;
成员变量:
1:任务队列 集合 需要控制线程安全问题
2:当前线程数量
3:核心线程数
4:最大线程数
5:任务队列的长度
成员方法:
1:提交任务;直接将任务添加到集合中(任务队列),超出就不让加了
2:执行任务;判断当前线程的数量,决定创建核心线程还是非核心线程(非核心线程 = 最大线程数量-核心线程数量)
*/
public class MyThreadPool {
//1:任务队列 集合 需要控制线程安全问题
private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
// 2:当前线程数量
private int num;
//3:核心线程数
private int corePoolSize;
//4:最大线程数
private int maxSize;
//5:任务队列的长度
private int workSize;
@Override
public String toString() {
return "MyThreadPool{" +
"tasks=" + tasks +
", num=" + num +
", corePoolSize=" + corePoolSize +
", maxSize=" + maxSize +
", workSize=" + workSize +
'}';
}
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
// 1. 提交任务
public void submit(Runnable r){
// 判断当前集合中任务的数量是否超出了最大任务数量
if(tasks.size() >= workSize){
System.out.println("任务:"+r+"被丢弃了");//饱和机制
}else {
tasks.add(r);
execTask(r);//直接将任务传给方法执行
}
}
//专门用于执行任务
private void execTask(Runnable r) {
// 判断当前线程池中线程总数量是否超出了最大核心数,在任务队列里面等待
if(num < corePoolSize){
// 创建线程
new MyWorker("核心线程:"+num,tasks).start();
num ++;//模拟创建了线程
}else if(num < maxSize){
new MyWorker("非核心线程:"+num,tasks).start();
num ++;//模拟创建了线程
}else {
System.out.println("任务:"+ r +"被缓存了。。。");
}
}
}
/*
测试类:
1.创建线程池类对象
2.提交多任务
*/
public class MyTest {
public static void main(String[] args) {
//1.创建线程池类对象
MyThreadPool pool = new MyThreadPool(2,4,20);//2个核心,2个非核心
// 2.提交多任务
for(int i = 0;i<10;i++){
// 3.创建任务对象,并提交给线程池
MyTask my = new MyTask(i);
pool.submit(my);
}
}
}
4. java内置线程池
4.1 ExecutorService 接口
该接口继承了Executor这个接口
import java.util.concurrent.*;
/*
练习异步计算结果
*/
public class FutureDemo {
public static void main(String[] args) {
// 1. 获取线程池对象
ExecutorService es = Executors.newCachedThreadPool();
// 2. 创建 Callable类型的任务对象
Future<Integer> f = es.submit(new MyCall(1,2));
// 3. 判断任务是否已经完成
boolean done = f.isDone();
System.out.println("第一次判断任务是否完成"+done);
boolean cancelled = f.isCancelled();
System.out.println("第一次判断任务是否取消"+cancelled);
try {
Integer integer = f.get();//一直等待任务的执行,直到完成
System.out.println("任务执行的结果:"+integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
boolean done2 = f.isDone();
System.out.println("第二次判断任务是否完成"+done2);
boolean cancelled2 = f.isCancelled();
System.out.println("第二次判断任务是否取消"+cancelled2);
}
}
class MyCall implements Callable<Integer>{
private int a;
private int b;
public MyCall(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public Integer call() throws Exception {
String name = Thread.currentThread().getName();
System.out.println(name+"准备开始计算。。。");
Thread.sleep(2000);//模拟需要2秒钟运算
System.out.println(name+"准备计算完成");
return a+b;
}
}
4.2 Executors工具类
可以从源码中看到Executors这个工具类包含了很多ExecutorService方法
案例一:Executors.newCachedThreadPool()
性能最大化,前提是服务器足够给力。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
练习 Executors 获取 ExecutorService,然后调用方法,提交任务
*/
public class MyTest01 {
public static void main(String[] args) {
// 1:使用工厂类获取线程池对象
ExecutorService es = Executors.newCachedThreadPool();
// 2:提交任务;任务可以是Runnable的对象,也可以是Callable
//一共 10个任务,创建了10个线程
for(int i =1;i<=10;i++){
es.submit(new MyRunnable1(i));
}
}
}
/*
任务类:包含任务编号,在任务中,打印是哪一个线程正在执行任务
*/
class MyRunnable1 implements Runnable{
//利用构造方法给任务编号
private int id;
public MyRunnable1(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("线程:"+Thread.currentThread().getName()+":执行了任务====>"+ id);
}
}
案例二:Executors.newFixedThreadPool(3);
让服务器压力小写,对性能要求不是那么高
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
练习 Executors 获取 ExecutorService,然后调用方法,提交任务
*/
public class MyTest01 {
public static void main(String[] args) {
// 1:使用工厂类获取线程池对象
// ExecutorService es = Executors.newCachedThreadPool();
//线程池里面最多 3个线程
ExecutorService es = Executors.newFixedThreadPool(3);
// 2:提交任务;任务可以是Runnable的对象,也可以是Callable
//一共 10个任务,创建了10个线程
for(int i =1;i<=10;i++){
es.submit(new MyRunnable1(i));
}
}
}
/*
任务类:包含任务编号,在任务中,打印是哪一个线程正在执行任务
*/
class MyRunnable1 implements Runnable{
//利用构造方法给任务编号
private int id;
public MyRunnable1(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("线程:"+Thread.currentThread().getName()+":执行了任务====>"+ id);
}
}
shutdown();
ExecutorService的子接口ScheduledExecutorService;用于延迟或定期执行任务
5 案例:秒杀商品
import java.util.concurrent.ThreadPoolExecutor;
/*
任务类:
包含了商品数量
客户名称
买手机的行为
*/
public class MyTask1 implements Runnable{
//商品的数量
private static int goods = 10;//保证商品的数量唯一
//表示客户名称
private String userName;
public MyTask1(String userName) {
this.userName = userName;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(userName+"正在使用"+name+"参与秒杀任务。。。");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (MyTask1.class){
if(goods > 0){// 判断商品是否被抢完
System.out.println(userName+"使用"+name+"秒杀:"+goods--+"号商品成功");
}else {
System.out.println(userName+"使用"+name+"秒杀失败啦!");
}
}
}
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyTask1Test {
public static void main(String[] args) {
// 1.创建线程池对象
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,1, TimeUnit.MINUTES,new LinkedBlockingDeque<>(15));
// 2. 循环创建任务对象,模拟20个用户
for(int i = 1;i<=20;i++){
MyTask1 myTask1 = new MyTask1("客户"+ i);
pool.submit(myTask1);
}
pool.shutdown();
}
}