Java-线程
大家好!接下来就由我来带大家学习线程的知识,相信大家也一定可以掌握!
线程相关概念
-
进程
- 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间。当我们使用迅雷,又启动一个进程,操作系统将为迅雷分配新的内存空间。
- 进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身产生、存在和消亡的过程。
-
单线程
- 同一时刻,只允许执行一个线程
-
多线程
- 同一时刻,可以执行多个线程,比如:一个QQ进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件
-
并发
- 同一时刻,多个任务交替执行,造成一种“
貌似同时
”的错觉,简单的说,单核cpu
实现的多任务就是并发。
- 同一时刻,多个任务交替执行,造成一种“
-
并行
- 同一个时刻,多个任务同时执行,多核
cpu
可以实现并行。
- 同一个时刻,多个任务同时执行,多核
一、什么是线程
- 线程是由进程创建的,是进程的一个实体
- 一个进程可以拥有多个线程
二、如何创建线程
-
继承
Thread
类,重写run
方法-
public class Thread01 { public static void main(String[] args) { // 创建Cat对象,可以当作线程使用 Cat cat = new Cat(); // 启动线程 cat.start(); } } /** * 1、当一个类继承了Thread类 ,该类就可以当做线程使用 * 2、我们会重写run方法 , 写上自己的业务代码 * 3、run Thread 类 实现了 Runnable 接口的 run方法 * */ /* @Override public void run() { super.run(); } * */ class Cat extends Thread{ int times = 0; @Override public void run() { while (times < 8){ times++; // 该线程每隔一秒输出我是小猫咪 System.out.println("我是小猫咪"+times); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
-
-
实现
Runnable
接口,重写run
方法- java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了
- java设计者门提供了另外一个方式创建线程,就是通过实现
Runnable
接口来创建线程
-
实现
Callable<V>
泛型接口,重写call()
方法-
需要使用
FutureTask
类来管理结果,在使用Thread
来开启线程 -
用来获取多线程执行的结果
-
public class Thread05 { public static void main(String[] args) throws Exception { /* * 多线程的第三种实现方式 * 特点:可以获取到多线程运行的结果 * 1、创建一个类MyCallable 实现 Callable接口 * 2、重写call (是有返回值的,表示多线程运行的结果) * * 3、创建MyCallable对象 (表示多线程要执行的任务) * 4、创建FutureTask 的对象 (作用管理多线程运行的结果) * 5、创建Thread类的对象,并启动 */ MyCallable myThread = new MyCallable(); FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(myThread); Thread thread = new Thread(integerFutureTask); thread.start(); System.out.println(integerFutureTask.get()); } } class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { // 实现 1 ~ 100 个数累加 Integer num = 0; for (int i = 0; i <= 100; i++) { num += i; } return num; } }
-
三、线程的基本执行流程
-
调用方法
public synchronized void start(){ start0(); }
-
start0()
是本地方法,是JVM
调用,底层是c/c++
实现-
真正实现多线程的效果,是
start0()
,而不是run
-
private native void start0();
-
public class Thread02 { public static void main(String[] args) { Dog dog = new Dog(); // dog.start() 不能直接调用 Thread thread = new Thread(dog); thread.start(); } } class Dog implements Runnable{ int count = 0; @Override public void run() { while (true){ System.out.println("小狗汪汪叫"+(++count)+Thread.currentThread().getName()); // 休息1秒 try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } if(count > 10){ break; } } } }
-
用代码模拟实现
Runnable
接口-
public class Thread02 { public static void main(String[] args) { Tiger tiger = new Tiger(); ThreadProxy threadProxy = new ThreadProxy(tiger); threadProxy.start(); } } class Animal {} class Tiger extends Animal implements Runnable{ @Override public void run() { System.out.println("老虎嗷嗷嗷"); } } // 线程代理类,模拟了极简的Thread类 class ThreadProxy implements Runnable{ private Runnable target = null; //属性Runnable public ThreadProxy(Runnable target) { this.target = target; } @Override public void run() { if(target != null){ target.run(); } } public void start(){ start0(); } public void start0(){ run(); } }
-
-
-
继承
Thread
和实现Runnable
的区别- 从
java
的设计来看,通过继承Thread
或者实现Runnable
接口来创建线程本质上没有区别,从官方文档我们可以看到Thread
类本身就实现了Runnable
接口 - 实现
Runnable
接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议使用Runnable
接口来实现多线程
- 从
四、线程终止
-
当线程完成任务后,自动退出
-
还可以通过使用变量来控制run方法退出,主线程控制子线程退出,通知方式,案例:
public class ThreadExit_ { public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); // 如果希望main线程去控制t1 线程的终止,必须可以修改 loop // 让t 退出run方法,从而终止 t1 线程 -> 通知方法 // 让主线程休息十秒在让t线程退出 Thread.sleep(10000); t.setLoop(false); } } class T extends Thread{ private int count = 0; private boolean loop = true; @Override public void run() { while (loop){ try { Thread.sleep(50); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("第"+(++count)+"循环"); } } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public boolean isLoop() { return loop; } public void setLoop(boolean loop) { this.loop = loop; } }
五、Thread类的常用方法
基础方法:
-
Thread.sleep(毫秒)
:让线程睡一会儿,暂停一会儿,静态方法 -
对象.start()
:开启线程 -
Thread.currentThread()
:获取当前线程对象 -
Thread.currentThread().getName()
:获取当前的线程名 -
setName()
:设置线程名称,使之与参数name
相同 -
run()
:调用线程对象的run
方法 -
setPriority()
: 更改线程的优先级 -
getPriority()
: 获取线程的优先级 -
interrupt()
: 中断线程注意:
start
底层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新的线程- 线程优先级的范围
interrrupt
,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程
例子:
public class ThreadMethod_ {
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
test.setName("小罗"); //设置名字
test.setPriority(Thread.MIN_PRIORITY); //设置优先级
test.start();
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
System.out.println("主线程 = "+i + "执行优先级="+test.getPriority());
}
test.interrupt();//中断线程休眠时间
}
}
class Test extends Thread{
@Override
public void run() {
while (true){
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " 吃个包子~~");
}
try {
System.out.println(Thread.currentThread().getName() + "休息中~~");
Thread.sleep(20*1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "被 interrupt 了");
}
}
}
}
提升方法:
-
yield
: 线程的礼让。让出cpu
,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功 -
join
: 线程的插队。插队的线程一旦插队成功,则肯定线执行完插入的线程所有的任务 -
isAlive()
:是否处于活动状态,判断线程是否存活,即还没有执行完毕 -
stop()
:终止线程,已取消,不建议使用。 -
interrupt()
:中断线程,用于打断阻塞状态的线程,如:sleep、wait、join- 如果被中断线程正在sleep,wait,join会导致被中断的线程抛出
InterruptedException
,并清除中断标记
;- 中断标记(状态)为 false
- 如果中断正在运行的线程,则会设置
中断标记
;- 中断标记(状态)为 true
park
的线程被中断,也会设置中断标记
- 如果被中断线程正在sleep,wait,join会导致被中断的线程抛出
-
isInterrupted()
:判断这个线程是否被中断-
boolean isInterrupted()
-
不会清除
中断标记
-
-
interrupted()
:判断当前线程是否被中断-
static boolean interrupted()
-
会清除
中断标记
-
六、用户线程和守护线程
-
用户线程:也叫做工作线程,当线程的任务执行完或通知方式结束
-
守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
-
常见的守护线程:垃圾回收机制
-
创建守护线程案例
myDaemonThread.setDaemon(true);
注意点:必须要在开启前进行设置
public class ThreadMethod02 { public static void main(String[] args) throws Exception { MyDaemonThread myDaemonThread = new MyDaemonThread(); myDaemonThread.setDaemon(true); myDaemonThread.start(); if (myDaemonThread.isDaemon()) { System.out.println("是守护线程"); } for (int i = 0; i < 10; i++) { Thread.sleep(1000); System.out.println("小叶在工作~~"); } } } class MyDaemonThread extends Thread{ @Override public void run() { for (;;){ try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("小罗和老龚在聊天--哈哈哈哈"); } } }
七、线程的生命周期
-
NEW
:尚未启动的线程 -
RUNNABLE
:在Java虚拟机
中执行的线程 ,可以细分为Ready
: 就绪状态Running
:真正在执行的状态
-
BLOCKED
:被阻塞等待监视器锁定的线程 -
WAITING
:正在等待另一个线程执行特定动作的线程 -
TIMED_WAITING
:正在等待另一个线程执行动作达到指定等待时间的线程 -
TERMINATED
:已退出的线程处于此状态
八、线程同步机制
Synchronized
-
在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。
-
也可以这样理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。
-
案例
public class HomeWork01 { public static void main(String[] args) throws InterruptedException { // 题目:使用三个线程分别随机 输出红绿蓝的颜色,RGB格式 0~255之间 RGB rgb = new RGB(); RGB rgb1 = new RGB(); RGB rgb2 = new RGB(); rgb.start(); rgb1.start(); rgb2.start(); } } class RGB extends Thread{ static int loop = 0; String[] rgb = new String[]{ "红色:","蓝色:","绿色:" }; @Override public synchronized void run() { //同一时刻只能有一个线程才能进入这个方法 System.out.println(rgb[loop++]+new Random().nextInt(256)); } }
九、线程锁执行原理
1、互斥锁
-
Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性
-
每个对象都对应与一个可称为 “互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
-
关键字
synchronized
来与对象的互斥锁联系,当某个对象用synchronized
修饰时表明该对象在任一时刻只能由一个线程访问 -
同步的局限性:导致程序的执行效率会降低
-
同步方法(非静态)的锁可以是this,也可以是其它对象(要求是同一个对象)
-
// 当前的方法中的锁就是当前的对象 public synchronized void m1(){} // public void m1 { // 这边就需要传入当前的对象 // 注意: // 如果是 new RGB().start(); // new RGB().start(); // 这样子开启两个线程的化是锁不住的,推荐下面的方法 synchronized(this){ System.out.println("hello"); } } // 需要的是同一个对象,不一定就是当前对象,下面这样子也可以完成同步效果 Object object = new Object(); public void m1 { // 这边就需要传入对象 synchronized(object){ System.out.println("hello"); } }
-
-
同步方法(静态的)的锁为当前类本身
-
/** * 静态方法中使用synchronized 中的锁是当前的SellTicket02.class */ public synchronized static void m1(){} /** * 如果要在方法里面加上synchronized 那么里面传入的就是当前类的class */ public synchronized static void m2(){ synchronized (SellTicket02.class){ System.out.println("hello"); } }
-
-
细节以及注意:
- 如果同步方法如果没有使用
static
修饰:默认锁对象为this
- 如果方法使用
static
修饰,默认锁对象:当前类.class - 实现的落地步骤:
- 需要分析上锁的代码
- 选择同步代码块或同步方法,尽量选择同步代码块,理论上来说同步的代码越少,效率越高
- 要求多个线程的锁对象为同一个即可
- 如果同步方法如果没有使用
2、线程死锁
-
解释
- 多个线程都占用了对象的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生
-
举例:
- 妈妈:你先完成作业,才让你玩手机
- 小明:你先让我玩手机,我才完成作业
-
案例:
-
public class DeadLock { public static void main(String[] args) { DeadLockDemo A = new DeadLockDemo(true); A.setName("A:"); DeadLockDemo B = new DeadLockDemo(false); B.setName("B:"); A.start(); B.start(); System.out.println(A.getName() +" " + A.getState()); System.out.println(B.getName()+" " + B.getState()); } } class DeadLockDemo extends Thread{ static Object o1 = new Object(); static Object o2 = new Object(); boolean flag; public DeadLockDemo(boolean flag){ this.flag = flag; } //下面的业务逻辑 //1、如果flag 为 true,线程A 就会得到/持有 o1 对象锁,然后尝试获取 o2 对象锁 //2、如果线程A 得不到 o2 对象锁 ,就会Blocked //3、如果flag 为 false 线程B 就会得到/持有 o2 对象锁,然后尝试获取 o1 对象锁 //4、如果线程B 得不到 o1 对象锁 ,就会Blocked @Override public void run() { if(flag){ synchronized (o1){ // 对象互斥锁 下面的代码是同步代码 System.out.println(Thread.currentThread().getName() + "进入 1"); synchronized (o2){ System.out.println(Thread.currentThread().getName() + "进入 2"); } } }else{ synchronized (o2){ System.out.println(Thread.currentThread().getName() + "进入 3"); synchronized (o1){ System.out.println(Thread.currentThread().getName() + "进入 4"); } } } } }
-
3、Lock锁
使用同步代码块虽然可以解决大部分问题,但是必须限制在synchronized
中,并不灵活,JDK5以后提供了一个新的锁对象Lock
-
Lock
实现提供比使用synchronized
方法和语句,更加便捷,灵活的锁定操作 -
Lock
中提供了获得锁和释放锁的方法 -
使用
Lock
的实现类ReentrantLock
可以进行操作 -
lock()
: 获得锁 -
unlock()
:释放锁 -
案例一:错误示范,某个线程还没还锁就跳出循环导致程序一直在运行
public class LockTest { public static void main(String[] args) { MyLock myLock1 = new MyLock(); MyLock myLock2 = new MyLock(); MyLock myLock3 = new MyLock(); myLock1.start(); myLock2.start(); myLock3.start(); } } /** * 买票 */ class MyLock extends Thread{ static int loop; static Lock lock = new ReentrantLock(); // 注意要使用 static 不然锁对象每个人都不一样就会出现问题 @Override public void run() { while (true){ lock.lock();// 获得锁 // 当我们的某个线程卖到第100张票后,就会直接带着锁跑了 if (loop == 100){ // 这里直接break出去了,还没来得及还锁,就会导致程序一直运行 break; }else{ try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } loop++; System.out.println(getName() + "卖出第"+loop +"张票"); } lock.unlock();// 释放锁 } } }
-
案例二:使用
finally
语句的特性来修复当前带着锁跑不还锁的代码class MyLock01 extends Thread{ static int loop; static Lock lock = new ReentrantLock(); // 注意要使用 static 不然锁对象每个人都不一样就会出现问题 @Override public void run() { while (true){ try { lock.lock();// 获得锁 // 当我们的某个线程卖到第100张票后,就会直接带着锁跑了 if (loop == 100){ // 这里直接break出去了,还没来得及还锁,就会导致程序一直运行 break; }else{ Thread.sleep(10); loop++; System.out.println(getName() + "卖出第"+loop +"张票"); } } catch (InterruptedException e) { throw new RuntimeException(e); }finally { // 使用finally语句的特性来优化释放锁 lock.unlock();// 释放锁 } } } }
4、释放锁
1、会释放锁
- 当前线程的同步方法、同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到
break
、retutn
. - 当前线程在同步代码块、同步方法中出现了
未处理的Error
或Exception
,导致异常结束 - 当前线程在同步代码块、同步方法中执行了线程对象的
wait()
方法,当前线程暂停,并释放锁。
2、不会释放锁
- 线程执行同步代码块或同步方法时,程序调用
Tread.sleep()
、Threa.yield()
方法暂停当前线程的执行,不会释放锁。 - 线程执行同步代码块时,其它线程调用了该线程的
suspend()
方法将该线程挂起,该线程不会释放锁。
十、等待唤醒机制
作用:在多线程编程中,等待唤醒机制(Wait-Notify Mechanism
)是一种重要的同步工具,主要用于解决线程之间的协作问题。
-
wait()
- 使当前线程进入等待状态,并释放当前对象的锁,当其他线程调用该对象的
notify()
或notifyAll()
方法时,当前线程可能会被唤醒 - 如果没有其他线程调用
notify()
或notifyAll()
方法,调用wait()
的线程将一直等待。
- 使当前线程进入等待状态,并释放当前对象的锁,当其他线程调用该对象的
-
notify()
- 唤醒一个正在等待当前对象锁的线程。如果有多个线程正在等待,JVM会随机选择一个线程进行唤醒。
- 被唤醒的线程不会立即恢复执行,它必须等待当前线程释放对象锁后才能继续执行。
-
notifyAll()
- 方法唤醒所有正在等待当前对象锁的线程。与
notify()
不同的是,notifyAll()
会唤醒所有等待的线程,而notify()
只会唤醒一个。 - 被唤醒的线程同样需要等待当前线程释放对象锁后才能继续执行。
- 方法唤醒所有正在等待当前对象锁的线程。与
-
生产者-消费者问题:这是等待唤醒机制最常见的应用场景之一。生产者线程负责生成数据并将其放入缓冲区,消费者线程负责从缓冲区中取出数据进行处理。当缓冲区为空时,消费者线程需要等待,直到生产者线程放入数据;当缓冲区已满时,生产者线程需要等待,直到消费者线程取出数据。通过等待唤醒机制,可以高效地协调生产者和消费者的行为。
-
案例:
import java.util.LinkedList; import java.util.Queue; public class ProducerConsumerExample { private final Queue<Integer> queue = new LinkedList<>(); private final int capacity; public ProducerConsumerExample(int capacity) { this.capacity = capacity; } // 生产者方法 public synchronized void put(int value) throws InterruptedException { while (queue.size() == capacity) { wait(); // 等待,直到缓冲区有空间 } queue.add(value); notifyAll(); // 唤醒等待的消费者线程 System.out.println("Produced: " + value + ", Queue size: " + queue.size()); } // 消费者方法 public synchronized int get() throws InterruptedException { while (queue.isEmpty()) { wait(); // 等待,直到缓冲区有数据 } int value = queue.poll(); notifyAll(); // 唤醒等待的生产者线程 System.out.println("Consumed: " + value + ", Queue size: " + queue.size()); return value; } public static void main(String[] args) { ProducerConsumerExample example = new ProducerConsumerExample(2); // 生产者线程 Thread producerThread = new Thread(() -> { try { for (int i = 0; i < 10; i++) { example.put(i); Thread.sleep((int) (Math.random() * 1000)); } } catch (InterruptedException e) { e.printStackTrace(); } }); // 消费者线程 Thread consumerThread = new Thread(() -> { try { for (int i = 0; i < 10; i++) { example.get(); Thread.sleep((int) (Math.random() * 1000)); } } catch (InterruptedException e) { e.printStackTrace(); } }); producerThread.start(); consumerThread.start(); } }
十一、线程池
- 常用线程池:
线程池类型 | 特点 | 适用场景 |
---|---|---|
FixedThreadPool | 线程池大小固定,可以有效控制线程的最大并发数 | 任务量可以预估并且线程数量不需要频繁变化的场景,如订单处理系统 |
CachedThreadPool | 线程池大小动态调整,空闲线程会被回收 | 执行大量短期小任务的场景,如高并发的Web应用 |
SingleThreadExecutor | 线程池中只有一个线程,保证任务顺序执行 | 需要保证任务顺序执行的场景,如日志记录系统 |
ScheduledThreadPool | 支持定时任务和周期性任务 | 定时任务调度,如定时清理数据库中的临时数据、定时发送邮件通知 |
- Java线程池的常用方法:
方法名称 | 描述 | 示例代码 |
---|---|---|
ExecutorService newFixedThreadPool(int nThreads) | 创建一个固定大小的线程池 | ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); |
ExecutorService newCachedThreadPool() | 创建一个可缓存线程池 | ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); |
ExecutorService newSingleThreadExecutor() | 创建一个单线程化的线程池 | ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); |
ScheduledExecutorService newScheduledThreadPool(int corePoolSize) | 创建一个支持定时及周期性任务执行的线程池 | ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); |
execute(Runnable command) | 提交一个不需要返回值的任务到线程池中执行 | fixedThreadPool.execute(() -> System.out.println("执行任务")); |
submit(Runnable task) | 提交一个不需要返回值的任务到线程池中执行,返回Future<?> | Future<?> future = fixedThreadPool.submit(() -> System.out.println("执行任务")); |
submit(Callable<T> task) | 提交一个有返回值的任务到线程池中执行,返回Future<T> | Future<String> future = fixedThreadPool.submit(() -> "任务返回值"); |
shutdown() | 尝试平滑地关闭线程池,等待已提交任务完成 | fixedThreadPool.shutdown(); |
shutdownNow() | 尝试立即关闭线程池,中断正在执行的任务 | List<Runnable> notExecutedTasks = fixedThreadPool.shutdownNow(); |
- 案例:
public class MyThreadPoolDemo {
public static void main(String[] args) {
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 使用线程池
executorService.submit(new ThreadTest());
executorService.submit(new ThreadTest());
executorService.submit(new ThreadTest());
}
}
class ThreadTest implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" : 你好!!"+i);
}
}
}
-
自定义线程池
- 参数一:核心线程数量 不能小于0
- 参数二:最大线程数 不能小于等于0,最大数量 >= 核心线程数量
- 参数三:空闲线程最大存活时间 不能小于0
- 参数四:时间单位
- 使用
TimeUnit
指定
- 使用
- 参数五:任务队列
- 不能为null
- 有两种阻塞队列,一种是有长度的,一种是没有长度的
new ArrayBlockingQueue<>(3)
: 有长度的new LinkedBlockingDeque<>()
: 没有长度的
- 参数六:创建线程工厂
- 不能为null
- 需要调用
Executors
里面的方法
- 参数七:任务的拒绝策略,一共有四种
- 不能为null
new ThreadPoolExecutor.AbortPolicy()
:默认策略:丢弃任务并抛出RejectedExecutionException
异常- 丢弃任务,但是不抛出异常,这是不推荐的做法
- 抛弃队列中等待最久的任务,然后把当前任务加入队列中
- 调用任务的
run()
方法绕过线程池直接执行
public class CustomizeThreadPoolDemo { public static void main(String[] args) { /* ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(); (核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略); 参数一:核心线程数量 不能小于0 参数二:最大线程数 不能小于等于0,最大数量 >= 核心线程数量 参数三:空闲线程最大存活时间 不能小于0 参数四:时间单位 使用TimeUnit指定 参数五:任务队列 不能为null 参数六:创建线程工厂 不能为null 参数七:任务的拒绝策略 不能为null */ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); threadPoolExecutor.submit(new ThreadTest()); threadPoolExecutor.submit(new ThreadTest()); } }
略);
参数一:核心线程数量 不能小于0
参数二:最大线程数 不能小于等于0,最大数量 >= 核心线程数量
参数三:空闲线程最大存活时间 不能小于0
参数四:时间单位 使用TimeUnit指定
参数五:任务队列 不能为null
参数六:创建线程工厂 不能为null
参数七:任务的拒绝策略 不能为null
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,
6,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
threadPoolExecutor.submit(new ThreadTest());
threadPoolExecutor.submit(new ThreadTest());
}
}