多线程
多线程相关概念
- 线程:
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位 - 进程:
进程是程序的基本执行实体 - 作用:
提供效率 - 并发:
在同一时刻,有多个指令在单个CPU上交替执行 - 并行:
在同一时刻,有多个指令在多个CPU上同时执行
多线程的实现方式
1、继承Thread类的方式进行实现
- main方法
public class ThreadDemo {
public static void main(String[] args) {
/*
多线程的第一种启动方式:
1、自己定义一个类继承Thread
2、重写run方法
3、创建子类的对象,并启动线程
*/
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("线程1: ");
t2.setName("线程2: ");
t1.start();
t2.start();
}
}
- 继承Thread类
public class MyThread extends Thread{
@Override
public void run(){
//书写线程要执行的代码
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "Hello World");
}
}
}
2、实现Runnable接口的方式进行实现
- main方法
public class RunnableDemo {
public static void main(String[] args) {
/*
多线程的第二种启动方式:
1、自己定义一个类实现Runnable接口
2、重写里面的run方法
3、参加自己的类的对象
4、参加一个Thread类对象,并开启线程
*/
//创建MyRunnable的对象
//表示多线程要执行的任务
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//给线程起名字
t1.setName("线程1: ");
t2.setName("线程2: ");
//开启线程
t1.start();
t2.start();
}
}
- 实现MyRunnable接口
public class MyRunnable implements Runnable{
@Override
public void run() {
//书写线程要执行的代码
//获取当前线程对象
//Thread t = Thread.currentThread();
for (int i = 0; i < 100; i++) {
//System.out.println(t.getName() + "Hello World");
System.out.println(Thread.currentThread().getName() + "Hello World");
}
}
}
3、利用Callable接口和Future接口方式实现
- main方法
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
多线程的第三种实现方式:
特点:可以获取到多线程运行的结果
1、创建一个类MyCallable实现Callable接口
2、重写call(是有返回值的,表示多线程运行的结果)
3、创建MyCallable的对象(表示多线程要执行的任务)
4、创建FutureTask的对象(表示管理多线程运行的结果)
5、创建Thread类的对象(表示线程)
*/
//创建MyCallable的对象(表示多线程要执行的任务)
MyCallable mc = new MyCallable();
//创建FutureTask的对象(表示管理多线程运行的结果)
FutureTask<Integer> ft = new FutureTask<>(mc);
//创建Thread类的对象(表示线程)
Thread t = new Thread(ft);
//启动线程
t.start();
//获取多线程运行的结果
Integer result = ft.get();
System.out.println(result);
}
}
- 实现Callable接口
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//求1~100之间的和
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
- 多线程三种实现方式对比
Thread类常见的成员方法
-
演示方法getName、setName、currentThread、sleep
-
main方法
public class ThreadDemo1 {
public static void main(String[] args) throws InterruptedException {
/*
给线程设置名字细节:
1、如果我们没有给线程设置名字,线程也是有默认的名字的
格式:Thread-X(X序号,从0开始)
2、如果我们要给线程设置名字,可以用set方法设置,也可以构造方法设置
*/
//1、创建线程对象
MyThread1 t1 = new MyThread1("线程1");
MyThread1 t2 = new MyThread1("线程2");
//2、开启线程
//t1.start();
//t2.start();
/*
currentThread细节:
1、当JVM虚拟机启动之后,会自动的启动多条线程
2、其中有一条线程就是main线程,它的作用就是去调用main方法,并执行里面的代码
*/
Thread t = Thread.currentThread();
String name = t.getName();
System.out.println(name);//main
/*
sleep方法细节:
1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
2、方法的参数:就表示睡眠的时间,单位毫秒 1秒=1000毫秒
3、当时间到了之后,线程会自动的醒来,继续执行下面的其它代码
*/
System.out.println("abc");
Thread.sleep(5000);
System.out.println("def");
}
}
- MyThread类
public class MyThread1 extends Thread{
public MyThread1() {
}
public MyThread1(String name) {
super(name);
}
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "@" + i);
}
}
}
线程的优先级
- main方法
public class ThreadDemo2 {
public static void main(String[] args){
MyThread2 t = new MyThread2();
Thread t1 = new Thread(t,"线程1");
Thread t2 = new Thread(t,"线程2");
//设置线程的优先级
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
- MyThread2类
public class MyThread2 implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
守护线程
- main方法
public class ThreadDemo3 {
public static void main(String[] args){
/*
setDaemon细节
当其它的非守护线程执行完毕后,守护线程会陆续结束
也就是说t3结束了,t4也就没有存在的必要了
因为t3循环次数少于t4,一般来说t4循环
不到100次就会提前结束
*/
MyThread3 t3 = new MyThread3();
MyThread4 t4 = new MyThread4();
t3.setName("线程3");
t4.setName("线程4");
//把第二个线程设置为守护线程
t4.setDaemon(true);
t3.start();
t4.start();
}
}
- MyThread3
public class MyThread3 extends Thread{
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(getName() + "---" + i);
}
}
}
- MyThread4
public class MyThread4 extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "---" + i);
}
}
}
线程礼让和插入线程
- 礼让线程
- main方法
public class ThreadDemo5 {
public static void main(String[] args){
MyThread5 t1 = new MyThread5();
MyThread5 t2 = new MyThread5();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
- MyThread5类
public class MyThread5 extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "---" + i);
//表示让出当前CPU的执行权
Thread.yield();
}
}
}
- 插入线程
- main方法
public class ThreadDemo6 {
public static void main(String[] args) throws InterruptedException {
MyThread6 t = new MyThread6();
t.setName("线程1");
t.start();
//表示把t这个线程,插入到当前线程之前
//t:线程1
//当前线程:main
t.join();
//执行在main线程当中
for (int i = 1; i <= 10; i++) {
System.out.println("main" + "---" + i);
}
}
}
- MyThread6类
public class MyThread6 extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "---" + i);
}
}
}
线程的生命周期
同步代码块
- 作用:把操作共享数据的代码锁起来
- 格式:
synchronized(锁){
操作共享数据的代码
}
- main方法
public class ThreadDemo7 {
public static void main(String[] args){
MyThread7 t1 = new MyThread7();
MyThread7 t2 = new MyThread7();
MyThread7 t3 = new MyThread7();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
- MyThread7类
public class MyThread7 extends Thread {
//表示这个类的所有对象都共享ticket数据
static int ticket = 0;
//锁对象一定要是唯一的
static Object obj = new Object();
@Override
public void run() {
while (true){
//同步代码块
synchronized (obj) {//也可以是MyThread7.class(因为该类的字节码文件是唯一的)
if (ticket < 100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName() + "正在卖第" + ticket + "张票!!!");
} else {
break;
}
}
}
}
}
同步方法
就是把synchronized关键字加到方法上
格式:
修饰符 synchronized 返回值类型 方法名(方法参数) {...}
特点1:同步方法是锁住方法里面所有的代码
特点2:锁对象不能自己指定
非静态:this
静态:当前类的字节码文件对象
- main方法
public class RunnableDemo1 {
public static void main(String[] args) {
MyRunnable1 mr = new MyRunnable1();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
- MyRunnable1类
public class MyRunnable1 implements Runnable {
int ticket = 0;
@Override
public void run() {
//1、循环
while (true) {
//2、同步代码块
try {
if (method()) break;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private synchronized boolean method() throws InterruptedException {
//3、判断共享数据是否到了末尾
if (ticket == 100) {
return true;
} else {
//4、判断共享数据是否到了末尾,如果没有到末尾
Thread.sleep(10);
ticket++;
System.out.println(Thread.currentThread().getName()
+ "正在卖第" + ticket + "票!!!");
}
return false;
}
}
Lock锁
- 作用:Lock实现提供比使用synchronize方法和语句可以获得更广泛的锁定操作
- Lock中提供了获得锁和释放锁的方法:
void lock(): 获得锁
void unlock(): 释放锁
- 注意:
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法:
ReentrantLock(): 创建一个ReentrantLock的实例 - main方法
public class ThreadDemo8 {
public static void main(String[] args){
MyThread8 t1 = new MyThread8();
MyThread8 t2 = new MyThread8();
MyThread8 t3 = new MyThread8();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
- MyThread8类(演示Lock锁)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread8 extends Thread {
//表示这个类的所有对象都共享ticket数据
static int ticket = 0;
//共享一个锁对象,要加static关键字
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//同步代码块
//synchronized (MyThread8.class) {
lock.lock();
try {
if (ticket < 100) {
Thread.sleep(10);
ticket++;
System.out.println(getName() + "正在卖第" + ticket + "张票!!!");
} else {
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();//防止在100次循环直接break掉没有释放锁,
// 所以将释放锁的代码放在finally语句中
}
//}
}
}
}
等待唤醒机制(生产者和消费者)
- 生产者消费者模式是一个十分经典的多线程协助的模式
常见方法
- main方法测试
public class ThreadDemo9 {
public static void main(String[] args) {
//创建线程对象
Cook c = new Cook();
Foodie f = new Foodie();
//给线程设置名字
c.setName("生产者");
f.setName("消费者");
//开启线程
c.start();
f.start();
}
}
Cook代码(生产者)
public class Cook extends Thread{
@Override
public void run() {
/*
1、循环
2、同步代码块
3、判断共享数据是否到了末尾(到了末尾)
4、判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)
*/
while (true){
synchronized (Desk.lock){
if(Desk.count == 0){
break;
}else {
//判断桌子上是否有食物
if(Desk.foodFlag == 1){
//如果有,就等待
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
//如果没有,就制作食物
System.out.println("厨师做了一碗面条");
//修改桌子上的食物状态
Desk.foodFlag = 1;
//叫醒等待的消费者开吃
Desk.lock.notifyAll();
}
}
}
}
}
}
- Foodie代码(消费者)
public class Foodie extends Thread {
@Override
public void run() {
/*
1、循环
2、同步代码块
3、判断共享数据是否到了末尾(到了末尾)
4、判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)
*/
while (true){
synchronized (Desk.lock){
if(Desk.count == 0){
break;
}else {
//先判断桌子上是否有面条
if(Desk.foodFlag == 0){
//如果没有,就等待
try {
Desk.lock.wait();//让当前线程跟锁进行判定
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
//把吃的总数-1
Desk.count--;
//如果有,就开吃
System.out.println("吃货正在吃面条,还能再吃" + Desk.count + "碗!!!");
//吃完之后,唤醒厨师继续做
Desk.lock.notifyAll();
//修改桌子的状态
Desk.foodFlag = 0;
}
}
}
}
}
}
- Desk代码(控制生产者和消费者)
public class Desk {
/*
作用:控制生产者和消费者的执行
*/
//是否有面条 0:没有面条 1:有面条
public static int foodFlag = 0;
//总个数
public static int count = 10;
//锁对象
public static Object lock = new Object();
}
等待唤醒机制(阻塞队列方式实现)
- put数据时:放不进去,会等着,也叫做阻塞
- take数据时:取出第一个数据,取不到会等着,也叫做阻塞
main方法(测试)
import java.util.concurrent.ArrayBlockingQueue;
public class ThreadDemo10 {
public static void main(String[] args) {
/*
需求:利用阻塞队列完成生产者和消费者的代码
*/
//细节:生产者和消费者必须使用同一个阻塞队列
//1、创建阻塞队列的对象
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
//2、创建线程对象,并把阻塞队列传递过去
Cook2 c = new Cook2(queue);
Foodie2 f = new Foodie2(queue);
//3、开启线程
c.start();
f.start();
}
}
- Cook2类(生产者)
import java.util.concurrent.ArrayBlockingQueue;
public class Cook2 extends Thread {
ArrayBlockingQueue<String> queue;
public Cook2(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true){
//不断的把面条放到阻塞队列当中
try {
queue.put("面条");
System.out.println("厨师做了一碗面条");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
- Foodie(消费者)
import java.util.concurrent.ArrayBlockingQueue;
public class Foodie2 extends Thread{
ArrayBlockingQueue<String> queue;
public Foodie2(ArrayBlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
while (true){
//不断从阻塞队列中获取面条
String food = null;
try {
food = queue.take();
System.out.println(food);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
线程的状态
- 注意:线程只有6种状态,没有运行状态
综合练习
1、抢红包
假设:100块,分成了3个包,现在有5个人去抢
其中,红包是共享数据
5个人是5条线程
打印结果如下:
×××抢到了×××元
×××抢到了×××元
×××抢到了×××元
×××没抢到
×××没抢到
- main方法(测试)
public class Test1 {
public static void main(String[] args) {
//创建线程的对象
MyThread9 t1 = new MyThread9();
MyThread9 t2 = new MyThread9();
MyThread9 t3 = new MyThread9();
MyThread9 t4 = new MyThread9();
MyThread9 t5 = new MyThread9();
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
t3.setName("线程3");
t4.setName("线程4");
t5.setName("线程5");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
- MyThread9类
import java.util.Random;
public class MyThread9 extends Thread{
//共享数据
//100块,分成3个包
static double money = 100;
static int count = 3;
//最小的中奖金额
static final double MIN = 0.01;
@Override
public void run() {
synchronized (MyThread9.class){
if(count == 0){
System.out.println(getName() + "没有抢到红包");
}else {
//判断,共享数据是否到了末尾(没有到末尾)
//定义一个变量,表示中奖的金额
double prize = 0;
if(count == 1){
//表示此时是最后一个红包
//就无需随机,剩余所有的钱都是中奖金额
prize = money;
}else {
//表示第一次,第二次随机
Random r = new Random();
//100元 3个包
//第一个红包:99.98
//100 - (3-1) * 0.01
double bounds = money - (count - 1) * MIN;
prize = r.nextDouble(bounds);
if(prize < MIN){
prize = MIN;
}
}
//从money当中,去掉当前中奖的金额
money = money - prize;
//红包的个数-1
count--;
//本次红包的信息进行打印
System.out.println(getName() + "抢到了" + prize + "元");
}
}
}
}
2、抽奖箱抽奖
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为
{10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1又产生了一个10元大奖
抽奖箱1又产生了一个100元大奖
抽奖箱1又产生了一个200元大奖
抽奖箱1又产生了一个800元大奖
抽奖箱2又产生了一个700元大奖
…
- main方法(测试)
import java.util.ArrayList;
import java.util.Collections;
public class Test2 {
public static void main(String[] args) {
//创建奖池
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
//创建线程
MyThread10 t1 = new MyThread10(list);
MyThread10 t2 = new MyThread10(list);
//设置名称
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
//启动线程
t1.start();
t2.start();
}
}
- MyThread10类
import java.util.ArrayList;
import java.util.Collections;
public class MyThread10 extends Thread{
ArrayList<Integer> list;
public MyThread10(ArrayList<Integer> list){
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (MyThread10.class) {
if (list.size() == 0) {
break;
}else {
//继续抽奖
Collections.shuffle(list);
int prize = list.remove(0);
System.out.println(getName() + "产生了一个" + prize + "元大奖");
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
3、在第二题的基础上继续完成如下需求:
每次抽的过程中,不打印,抽完时一次性打印(随机)
在这次抽奖过程中,抽奖箱1总共产生了6个奖项。
分别为:10,20,100,500,2,300最高奖项为300元,总计金额为932元
这次抽奖过程中,抽奖箱2总共产生了6个奖项。
分别为:5,50,200,800,80,700最高奖项为800元,总计金额为1835元
- main方法(测试)
import java.util.ArrayList;
import java.util.Collections;
public class Test3 {
public static void main(String[] args) {
//创建奖池
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
//创建线程
MyThread11 t1 = new MyThread11(list);
MyThread11 t2 = new MyThread11(list);
//设置名称
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
//启动线程
t1.start();
t2.start();
}
}
- MyThread11类(线程栈的方式实现)
import java.util.ArrayList;
import java.util.Collections;
public class MyThread11 extends Thread{
ArrayList<Integer> list;
public MyThread11(ArrayList<Integer> list){
this.list = list;
}
@Override
public void run() {
ArrayList<Integer> boxList = new ArrayList<>();//1 //2
while (true) {
synchronized (MyThread11.class) {
if (list.size() == 0) {
System.out.println(getName() + boxList);
break;
}else {
//继续抽奖
Collections.shuffle(list);
int prize = list.remove(0);
boxList.add(prize);
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
4、在第三题的基础上继续完成如下需求:
在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元
- main方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建奖池
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
//创建多线程要运行的参数对象
MyCallable1 mc = new MyCallable1(list);
//创建多线程运行结果的管理者对象
//线程1
FutureTask<Integer> ft1 = new FutureTask<>(mc);
//线程2
FutureTask<Integer> ft2 = new FutureTask<>(mc);
//创建线程
Thread t1 = new Thread(ft1);
Thread t2 = new Thread(ft2);
//设置名称
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
//启动线程
t1.start();
t2.start();
int max1 = ft1.get();
int max2 = ft2.get();
if(max1 == max2){
System.out.println("在此次抽奖过程中,抽奖箱1和抽奖箱2都产生了最大奖项"+max1+"元");
} else if (max1 > max2) {
System.out.println("在此次抽奖过程中,抽奖箱1产生了最大奖项"+max1+"元");
}else {
System.out.println("在此次抽奖过程中,抽奖箱2产生了最大奖项"+max2+"元");
}
}
}
- MyCallable1类(使用Callable创建线程,获取返回值)
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;
public class MyCallable1 implements Callable<Integer> {
ArrayList<Integer> list;
public MyCallable1(ArrayList<Integer> list) {
this.list = list;
}
@Override
public Integer call() throws Exception {
ArrayList<Integer> boxList = new ArrayList<>();//1 //2
while (true) {
synchronized (MyCallable1.class) {
if (list.size() == 0) {
System.out.println(Thread.currentThread().getName() + boxList);
break;
}else {
//继续抽奖
Collections.shuffle(list);
int prize = list.remove(0);
boxList.add(prize);
}
}
Thread.sleep(10);
}
if(boxList.size() == 0){
return null;
}else {
return Collections.max(boxList);
}
}
}
线程池
- 线程池核心原理:
1、创建一个池子,池子是空的
2、提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
3、但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待 - 线程池代码实现
1、创建线程池
2、提交任务
3、所有的任务全部执行完毕,关闭线程池
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象。
- main方法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo {
public static void main(String[] args) {
//1、获取线程池对象
ExecutorService pool1 = Executors.newFixedThreadPool(3);
//ExecutorService pool2 = Executors.newCachedThreadPool();//没有上限的线程池
//2、提交任务
pool1.submit(new MyRunnable2());
pool1.submit(new MyRunnable2());
pool1.submit(new MyRunnable2());
pool1.submit(new MyRunnable2());//排队等待
//3、销毁线程池
pool1.shutdown();
}
}
- MyRunnable2类
public class MyRunnable2 implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
自定义线程池
任务拒绝策略
import java.util.concurrent.*;
public class MyThreadPoolDemo1 {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,//核心线程数量,不能小于0
6,//最大线程数,不能小于0,最大数量 >= 核心线程数量
60,//空闲线程最大存活时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
);
}
}
小结:
1、创建一个空的池子
2、有任务提交时,线程池会创建线程去执行任务,执行完毕归还线程
- 不断的提交任务,会有以下三个临界点:
1、当核心线程满时,再提交任务就会排队
2、当核心线程满,队伍满时,会创建临时线程
3、当核心线程满,队伍满,临时线程满时,会触发任务拒绝策略 - 线程池多大合适
public class MyThreadPoolDemo3 {
public static void main(String[] args) {
//向Java虚拟机返回可用处理器的数目
int count = Runtime.getRuntime().availableProcessors();
System.out.println(count);//12(最大并行数)
}
}