线程
创建线程的三种方式
继承Thread类
实现Runnable接口
实现Callable接口
线程状态
线程方法
停止线程
线程休眠----sleep
线程礼让----yield
两个线程t1、t2,t1线程调用yield方法,t1线程进入就绪状态,等t2线程运行结束后再运行t1线程
线程强制执行----jion
线程的优先级
线程池
什么是线程池
为什么使用线程池
使用场景
线程池参数介绍
- corePoolSize: 核心线程数量,当有一个任务提交到线程池的时候,如果当前线程池的线程数量没有达到核心线程数量,则创建线程来执行任务
- maximunPoolSize: 最大线程数量,当有一个任务提交到线程池的时候,如果当前线程池的线程数量达到了核心线程的数量,并且任务队列也已经满了,则再在满足线程池最大线程数量的前提下,创建线程执行该任务,如果任务队列没有满,则该任务进入任务队列等该
- keepAliveTime: 空闲线程的存活时间,当一个线程没有执行任务时(闲置时),能够存活的时间是多少,如果超过存活时间,则会被线程池回收
- unit:空闲线程的存活时间的单位
- workQueue:任务队列,当线程的数量达到线程池的核心线程数量,这个时候再有任务提交到线程池的时候,就会把这些任务加到任务队列里,如果任务队列也满了但线程数量没有达到最大线程数量,则会创建新的线程来执行任务
- threadFactory:线程工厂,创建线程的工厂,允许我们自己参与创建线程的过程
- handler:拒绝策略,当线程数量达到核心线程数量和最大线程数量,并且任务队列也存满了,线程池处于饱和状态,如果这个时候,还有任务提交到线程池,这个时候采取拒绝策略,是将这些任务丢弃还是让这些任务等待
线程池工作流程介绍
参数设计分析
自定义线程池例子
创建任务类
package thread;
/**
* 创建任务类,实现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) {
throw new RuntimeException(e);
}
System.out.println("线程 " + name + " 完成了任务 " + id);
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
创建线程类
package thread;
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();
}
}
}
创建线程池类
package thread;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* 这是自定义的线程池类
* 成员变量:
* 1. 任务队列 集合 需要控制线程安全
* 2. 当前线程数量
* 3. 核心线程数
* 4. 最大线程数
* 5. 任务队列的长度
*
* 成员方法:
* 1. 提交任务,将任务添加到集合中,需要判断任务是否超出了任务长度
* 2. 执行任务,判断当前线程的数量,决定创建核心线程还是非核心线程
*/
public class MyThreadPool {
// 1. 任务队列 Collections.synchronizedList() 宝成创建出来的集合线程是安全的
private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
// 当前线程数量
private int num;
// 核心线程数量
private int corePoolSize;
// 最大线程数量
private int maxSize;
// 任务队列的长度
private int workSize;
public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.workSize = workSize;
}
// 提交任务
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 + "被缓存了......");
}
}
}
测试类
package thread;
/**
* 测试类:
* 1. 创建线程池类对象
* 2. 提交多个任务
*/
public class MyTest {
public static void main(String[] args) {
// 创建线程池对象
MyThreadPool pool = new MyThreadPool(2, 4, 20);
// 提交任务
for (int i = 0; i < 30; i++) {
// 创建任务对象,提交给线程池
MyTask my = new MyTask(i);
pool.submit(my);
}
}
}
ExecutorService
newCachedThreadPool
package newCachedThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* 联系Executor,获取ExecutorService,然后调用方法,提交任务
*/
public class MyTest01 {
public static void main(String[] args) {
// test1();
test2();
}
// 练习newCachedThreadPool方法
private static void test1() {
// 1. 使用工厂类获取线程池对象
ExecutorService es = Executors.newCachedThreadPool();
// 2. 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
// 练习newCachedThreadPool重载方法
private static void test2() {
// 1. 使用工厂类获取线程池对象
ExecutorService es = Executors.newCachedThreadPool(new ThreadFactory() {
int n = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "自定义线程名称 " + n++);
}
});
// 2. 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
}
/**
* 任务类
* 包含一个任务编号
* 在任务中打印出是哪一个线程正在执行任务
*/
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(name + " 执行了任务....." + id);
}
}
newFixedThreadPool
package newFixedThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class Test01 {
public static void main(String[] args) {
// test1();
test2();
}
// 练习newFixedThreadPool方法
private static void test1() {
// 使用工厂类获取线程池对象
ExecutorService es = Executors.newFixedThreadPool(3);
// 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
// 练习newFixedThreadPool重载方法
private static void test2() {
// 使用工厂类获取线程池对象
ExecutorService es = Executors.newFixedThreadPool(3, new ThreadFactory() {
int i = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "自定义线程名称 " + i++);
}
});
// 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
}
// 这是一个任务类,包含任务编号
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(name + " 执行了任务....." + id);
}
}
newSingleThreadExecutor
package newSingleThreadExector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class Test {
public static void main(String[] args) {
// test1();
test2();
}
// 练习newSingleThreadExecutor方法
private static void test1() {
// 使用工厂类获取线程池
ExecutorService es = Executors.newSingleThreadExecutor();
// 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
// 练习newSingleThreadExecutor重载方法
private static void test2() {
// 使用工厂类获取线程池
ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFactory() {
int i = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "自定义线程 " + i ++);
}
});
// 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
}
}
/**
* 任务类,包含任务编号
*/
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(name + " 执行了任务....." + id);
}
}
ExecutorService中的shutdown和shutdownNow方法
package threadPool;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 练习Executor获取ExecutorService,测试关闭线程池的方法
*/
public class Test01 {
public static void main(String[] args) {
// 使用工厂类获取线程池
ExecutorService es = Executors.newSingleThreadExecutor();
// 提交任务
for (int i = 0; i < 10; i++) {
es.submit(new MyRunnable(i));
}
// 关闭线程池,仅仅是不再接收新的任务,以前的任务还是会继续执行
// es.shutdown();
// es.submit(new MyRunnable(55)); // 不允许再提交新的任务
// 立刻关闭线程池,如果线程池中还有缓存的任务,没有执行,则取消执行,并返回这些任务
List<Runnable> list = es.shutdownNow();
list.forEach(i -> System.out.println(i));
}
}
/**
* 任务类,包含任务编号
*/
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(name + " 执行了任务....." + id);
}
@Override
public String toString() {
return "MyRunnable{" +
"id=" + id +
'}';
}
}
ScheduledExecutorService