敏而好学,不耻下问。
一、基本概念
进程:是正在运行的程序
- 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
- 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
- 并发性:任何进程都可以同其他进程一起并发执行
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
多线程的应用场景:
并发:在同一时刻,有多个指令在单个cpu上交替执行
并行:在同一时刻,有多个指令在多个cpu上同时执行
二、实现多线程
实现方式一:继承Thread类
步骤
- 自定义一个类继承
Thread
- 重写
run
方法
- 创建子类的对象,并使用
start
方法启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class ThreadDemo { public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.setName("线程1"); t2.setName("线程2"); t1.start(); t2.start(); } }
---------------
public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(this.getName() + ": Hello world"); } } }
|
线程1: Hello world
线程2: Hello world
线程1: Hello world
线程1: Hello world
线程1: Hello world
线程1: Hello world
线程1: Hello world
······
「可以看到输出是两个线程交替进行的」
实现方式二:实现Runnable接口
步骤
- 自己定义一个类实现Runnable接口
- 重写里面的run方法
- 创建自己的类的对象
- 创建一个Thread类的对象,并开启线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class ThreadDemo { public static void main(String[] args) { MyRun r = new MyRun(); Thread t1 = new Thread(r); Thread t2 = new Thread(r);
t1.setName("线程1"); t2.setName("线程2");
t1.start(); t2.start(); } }
------ public class MyRun implements Runnable{
@Override public void run() { for (int i = 0; i < 100; i++) { Thread t = Thread.currentThread(); System.out.println(t.getName() + ": hello world"); } } }
|
线程2: hello world
线程1: hello world
线程2: hello world
线程2: hello world
线程2: hello world
线程2: hello world
······
「可以看到输出也是两个线程交替进行的」
实现方式三:利用Callable接口和Future接口
步骤
- 创建一个类MyCallable实现Callable接口
- 重写call(是有返回值的,表示多线程的运行结果)
- 创建MyCallable的对象(表示多线程的要执行的任务)
- 创建FutureTask的对象(作用管理多线程的的运行结果)
- 创建Thread类的对象,并启动(表示线程)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class ThreadDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<>(mc); Thread t1 = new Thread(ft); t1.start(); Integer result = ft.get(); System.out.println(result); } }
-------
public class MyCallable implements Callable<Integer> {
@Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } return sum; } }
|
5050

常见的成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package a04threadmethod;
public class ThreadDemo { public static void main(String[] args) throws InterruptedException { MyThread t1 = new MyThread("ucas"); MyThread t2 = new MyThread("nssc");
t1.start(); t2.start();
} }
------- package a04threadmethod;
public class MyThread extends Thread{
public MyThread() { }
public MyThread(String name) { super(name); }
@Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(getName() + "@ " + i); } } }
|
抢占式调度,在jvm中,线程的优先级从1-10,默认为5,优先级越高,被选中执行的概率越大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class ThreadDemo { public static void main(String[] args) { MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "ucas");
Thread t2 = new Thread(mr, "nssc");
t1.setPriority(1); t2.setPriority(10);
t1.start(); t2.start(); } }
------- public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println(Thread.currentThread().getName() + "---" + i); } } }
|
守护线程:当其他的非守护线程执行完毕之后,守护线程会陆续结束
应用场景:在qq聊天界面中,聊天消息接发为线程1,文件传输中为线程2,当关闭聊天窗口时,如果线程2为守护线程,那么即使聊天窗口关闭(线程1结束),线程2仍会执行一直到完毕
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class MyThread1 extends Thread{ @Override public void run() { for (int i = 1; i <= 10; i++) { System.out.println(getName() + "@" + i); } } }
------ public class MyThread2 extends Thread{ @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println(getName() + "@" + i); } } }
------ public class ThreadDemo { public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); MyThread1 t2 = new MyThread1(); MyThread2 t3 = new MyThread2();
t1.setName("女神1"); t2.setName("女神2"); t3.setName("备胎");
t3.setDaemon(true);
t1.start(); t2.start(); t3.start(); } }
|
线程的生命周期

Q:sleep方法会让线程睡眠,睡眠时间到了之后,立马就会执行该线程的代码吗?
A:不会,此时线程会进入就绪状态,需要抢夺刀cpu的执行权后才能执行
三、线程安全问题
需求:某电影院正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class MyThread extends Thread{
static int ticket = 0;
@Override public void run() { while(true){ if(ticket < 100){ ticket ++; System.out.println(getName() + "正在卖第" + ticket + "张票!!!"); } else { break; } } } }
------ public class ThreadDemo { public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread();
t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3");
t1.start(); t2.start(); t3.start();
} }
|
······
窗口2正在卖第96张票!!!
窗口2正在卖第97张票!!!
窗口3正在卖第94张票!!!
窗口3正在卖第99张票!!!
窗口3正在卖第100张票!!!
窗口1正在卖第90张票!!!
窗口2正在卖第99张票!!!
我们可以看出这样是有问题的,同一张票被两个窗口卖出过,于是我们就需要对共享数据上锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MyThread extends Thread{
static int ticket = 0;
static Object obj = new Object();
@Override public void run() { while(true){ synchronized(obj){ if(ticket < 100){ ticket ++; System.out.println(getName() + "正在卖第" + ticket + "张票!!!"); } else { break; } } } } }
|
注意:
synchronized
的地方要写对,什么时候上锁是有讲究的,例如如果上面的例子,锁上在while外面的话,结果将是窗口1卖完所有的100张票就直接结束了
- 锁对象可以任意,但是一定要保持唯一,这是因为,要保证所有线程看到的都是同一把锁
同步方法:将synchronized
关键字加到方法上
特点1:同步方法是锁住方法里面的所有代码
特点2:锁对象不能自己指定 如果是非静态方法,锁对象为this
,如果是静态方法,锁对象为当前类的文件对象
对上述需求使用同步方法完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package a05threadsafe1;
public class MyThread extends Thread{
static int ticket = 0;
static Object obj = new Object();
@Override public void run() { while(true){ synchronized(obj){ try { if (method()) break; } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
private boolean method() throws InterruptedException { if(ticket < 100){ Thread.sleep(100); ticket ++; System.out.println(getName() + "正在卖第" + ticket + "张票!!!"); } else { return true; } return false; } }
|
四、Lock锁
Lock中提供了获得锁和释放锁的方法
获得锁:void lock()
释放锁:void unlock()
由于Lock
是接口,不能直接实例化,于是采用它的实现类ReentrantLock
来实例化
1 2 3 4 5 6 7 8 9 10
| static Lock lock = new ReentrantLock();
lock.lock(); try { } catch (InterruptedException e){ e.printStackTrace(); } finally { lock.unlock(); }
|
五、死锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Demo { public static void main(String[] args) { Object objA = new Object(); Object objB = new Object();
new Thread(()->{ while(true){ synchronized (objA){ synchronized (objB){ System.out.println("小康同学正在走路"); } } } }).start();
new Thread(()->{ while(true){ synchronized (objB){ synchronized (objA){ System.out.println("小薇同学正在走路"); } } } }).start(); } }
|
六、生产者和消费者(等待唤醒机制)
方法名称 |
说明 |
void wait() |
当前线程等待,直到被其他线程唤醒 |
void notify() |
随机唤醒单个线程 |
void notifyAll() |
唤醒所有线程 |

需求:完成生产者和消费者(等待唤醒机制)的代码,实现线程轮流交替执行的结果
ThreadDemo.java
1 2 3 4 5 6 7 8
| public class ThreadDemo { public static void main(String[] args) { Foodie foodie = new Foodie(); Cook cook = new Cook(); foodie.start(); cook.start(); } }
|
Desk.java
1 2 3 4 5 6 7 8 9 10 11 12
| public class Desk {
public static int foodFlag = 0;
public static int count = 10;
public static Object lock = new Object(); }
|
Foodie.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Foodie extends Thread{ @Override public void run() {
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 { Desk.count --; System.out.println("正在吃面条,还能吃" + Desk.count + "碗!!!"); Desk.lock.notify(); Desk.foodFlag = 0; } } } } } }
|
Cook.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Cook extends Thread{ @Override public void run() {
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.lock.notify(); Desk.foodFlag = 1; } } } } } }
|
厨师做了一碗面条
正在吃面条,还能吃9碗!!!
厨师做了一碗面条
正在吃面条,还能吃8碗!!!
厨师做了一碗面条
正在吃面条,还能吃7碗!!!
厨师做了一碗面条
正在吃面条,还能吃6碗!!!
厨师做了一碗面条
正在吃面条,还能吃5碗!!!
厨师做了一碗面条
正在吃面条,还能吃4碗!!!
厨师做了一碗面条
正在吃面条,还能吃3碗!!!
厨师做了一碗面条
正在吃面条,还能吃2碗!!!
厨师做了一碗面条
正在吃面条,还能吃1碗!!!
厨师做了一碗面条
正在吃面条,还能吃0碗!!!
使用阻塞队列实现

阻塞队列底层就是用锁实现的,于是不用开发者手动加锁
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.util.concurrent.ArrayBlockingQueue;
public class ThreadDemo { public static void main(String[] args) { ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
Cook c = new Cook(queue); Foodie f = new Foodie(queue);
c.start(); f.start();
} }
|
Foodie.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.util.concurrent.ArrayBlockingQueue;
public class Foodie extends Thread{
ArrayBlockingQueue<String> queue;
public Foodie(ArrayBlockingQueue<String> queue) { this.queue = queue; }
@Override public void run() { while (true) { try { String food = queue.take(); System.out.println(food); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
|
Cook.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import java.util.concurrent.ArrayBlockingQueue;
public class Cook extends Thread{ ArrayBlockingQueue<String> queue;
public Cook(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); } } } }
|
线程的六大状态
新建状态(NEW) -------> 创建线程对象
就绪状态(RUNNABLE) ------> start方法
阻塞状态 (BLOCKED) ------> 无法获得锁对象
等待状态(WAITING) ------> wait方法
计时等待(TIMED_WAITING) ------> sleep方法
结束状态(TERMINATED) ------> 全部代码运行完毕
七、多线程练习题
练习01
需求:一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
要求:请用多线程模拟卖票过程并打印剩余电影票的数量
MyThread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MyThread extends Thread{ public static int count = 1000; @Override public void run() { while (true) { synchronized (MyThread.class) { if(count == 0){ break; } else { try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(getName() + "卖出一张票"); count --; System.out.println("当前剩余票数:" + count + "张"); } } }
} }
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ThreadDemo { public static void main(String[] args) {
MyThread t1 = new MyThread(); MyThread t2 = new MyThread();
t1.setName("窗口1"); t2.setName("窗口2");
t1.start(); t2.start();
} }
|
练习02
需求:有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出,利用多 线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.
MyRun.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class MyRun implements Runnable{
public int count = 100;
@Override public void run() { while (true){ synchronized (MyRun.class) { if(count <= 10) break; else { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } count --; System.out.println(Thread.currentThread().getName() + "正在发送礼品... 此时礼品剩余数量" + count); } } } } }
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import a08practice01.MyThread;
public class ThreadDemo { public static void main(String[] args) {
MyRun mr = new MyRun(); Thread t1 = new Thread(mr); Thread t2 = new Thread(mr);
t1.setName("窗口1"); t2.setName("窗口2");
t1.start(); t2.start();
} }
|
练习03
需求:同时开启两个线程,共同获取1-100之间的所有数字。要求:将输出所有的奇数。
MyRun.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class MyRun implements Runnable{
public int num = 100;
@Override public void run() { while (true){ synchronized (MyRun.class){ if(num < 1) break; else { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } if(num % 2 == 1) System.out.println(Thread.currentThread().getName() + "@ " + num); num --; } } } } }
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package a08practice03;
public class ThreadDemo { public static void main(String[] args) {
MyRun mr = new MyRun(); Thread t1 = new Thread(mr); Thread t2 = new Thread(mr); t1.setName("窗口1"); t2.setName("窗口2"); t1.start(); t2.start(); } }
|
练习04
抢红包
1 2 3 4 5 6 7 8 9 10 11
| 需求: 微信中的抢红包也用到了多线程。 假设:100块,分成了3个包,现在有5个人去抢。 其中,红包是共享数据。 5个人是5条线程。 打印结果如下: XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.util.ArrayList; import java.util.List; import java.util.Random;
public class ThreadDemo { public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); MyThread t5 = new MyThread(); t1.setName("苏无名"); t2.setName("樱桃"); t3.setName("卢凌风"); t4.setName("裴喜君"); t5.setName("费鸡师"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
|
MyThread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import java.util.Random;
public class MyThread extends Thread{
static int money = 10000; static int num = 3; static final int MIN = 1;
@Override public void run() { synchronized (MyThread.class){ if(num <= 0) { System.out.println("很遗憾~" + getName() + "没有抢到红包~"); } else { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } int prize = 0; if(num == 1) prize = money; else { Random r = new Random(); int bounds = money - (num - 1) * MIN; prize = r.nextInt(bounds); if(prize < MIN) prize = MIN; } money -= prize; num --; System.out.println("恭喜 " + getName() + " 抢到红包" + prize / 100.0 + "元!!!"); } } } }
|
练习05
抽奖箱抽奖
1 2 3 4 5 6 7 8 9 10
| 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2” 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 每次抽出一个奖项就打印一个(随机) 抽奖箱1 又产生了一个 10 元大奖 抽奖箱1 又产生了一个 100 元大奖 抽奖箱1 又产生了一个 200 元大奖 抽奖箱1 又产生了一个 800 元大奖 抽奖箱2 又产生了一个 700 元大奖 .....
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import a08practice05.MyThread;
import java.util.ArrayList; import java.util.Collections;
public class ThreadDemo { 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); MyThread t1 = new MyThread(list); MyThread t2 = new MyThread(list); t1.setName("抽奖箱1"); t2.setName("抽奖箱2"); t1.start(); t2.start(); } }
|
MyThread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.util.ArrayList; import java.util.Collections;
public class MyThread extends Thread{ ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) { this.list = list; }
@Override public void run() { while(true){ synchronized (MyThread.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); } }
} }
|
练习06
多线程统计并求最大值
1 2 3 4 5 6 7
| 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700}; 创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2” 随机从抽奖池中获取奖项元素并打印在控制台上,格式如下: 每次抽的过程中,不打印,抽完时一次性打印(随机) 在此次抽奖过程中,抽奖箱1总共产生了6个奖项。 分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元 在此次抽奖过程中,抽奖箱2总共产生了6个奖项。 分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元
|
ThreadDemo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import java.util.ArrayList; import java.util.Collections;
public class ThreadDemo { 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); MyThread t1 = new MyThread(list); MyThread t2 = new MyThread(list); t1.setName("抽奖箱1"); t2.setName("抽奖箱2"); t1.start(); t2.start(); } }
|
MyThread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import java.util.ArrayList; import java.util.Collections;
public class MyThread extends Thread{
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) { this.list = list; }
@Override public void run() { ArrayList<Integer> boxlist = new ArrayList<>(); while(true){ synchronized (a08practice05.MyThread.class){ if(list.size() == 0) { boxlist.sort(Integer::compareTo); int MAX = boxlist.get(boxlist.size() - 1); int sum = boxlist.stream().mapToInt(Integer::intValue).sum(); System.out.println("抽奖箱1"+ boxlist + " 最高金额 " + MAX + " 总金额 " + sum); break; } else { Collections.shuffle(list); int prize = list.remove(0); boxlist.add(prize); } } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
|
八、线程池
线程池主要核心原理:
- 创建一个池子,池子是空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下次在提交任务时,不需要创建新的线程,直接复用已有的线程即可
- 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等候
线程池实现步骤
-
创建线程池
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
方法名称 |
说明 |
public static ExecutorService newCachedThreadPool() |
创建一个没有上限的线程池 |
public static ExecutorService new FixedThreadPool(int nThreads) |
创建有上限的线程池 |
-
提交任务
-
所有的任务全部执行完毕,关闭线程池
九、自定义线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
参数一:核心线程数量 不能小于0
参数二:最大线程数 不能小于0,最大数量 >= 核心线程数量
参数三:空闲线程最大存活时间 不能小于0
参数四:时间单位 用TimeUnit指定
参数五:任务队列 不能为null
参数六:创建线程工厂 不能为null
参数七:任务的拒绝策略 不能为null
1 2 3 4 5 6 7 8 9
| ThreadPoolExecutor pool = new ThreadPoolExecutor( 3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );
|

不断的提交任务,会有三个临界点:
- 当核心线程满时,在提交任务就会排队
- 当核心线程满,队伍满时,会创建临时线程
- 当核心线程满,队伍满时,临时线程满时,会触发任务拒绝策略