进程 线程
- 进程 正在运行程序的实例 进程包含了线程 每一个线程执行不同的任务
- 不同的进程使用不同的内存空间 在当前进程下的使用线程可以共享内存间
- 线程更轻量 线程上下文切换成本一般比进程上下文切换低
并行 并发
- 并行 同一时间动手做多件事情的能力
- 多个人 同时做不同的事情
- 并发 同一时间应对多件事情的能力
- 一个人 洗衣做饭 交替轮流做这件事
创建线程的方式
- 继承Thread类
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 16:48
*/
public class extendthread extends Thread{
@Override
public void run() {
System.out.println("通过继承thread创建多线程"+Thread.currentThread().getName());
}
public static void main(String[] args) {
extendthread thread1 = new extendthread();
extendthread thread2 = new extendthread();
extendthread thread3 = new extendthread();
extendthread thread4 = new extendthread();
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=8317:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.extendthread
通过继承thread创建多线程Thread-0
通过继承thread创建多线程Thread-1
通过继承thread创建多线程Thread-2
通过继承thread创建多线程Thread-3
- 实现runnable接口
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 16:52
*/
public class implementsrunable implements Runnable{
@Override
public void run() {
System.out.println("通过实现runnable接口创建多线程"+Thread.currentThread().getName());
}
public static void main(String[] args) {
implementsrunable impl = new implementsrunable();
Thread thread1 = new Thread(impl);
Thread thread2 = new Thread(impl);
Thread thread3 = new Thread(impl);
Thread thread4 = new Thread(impl);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=8370:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.implementsrunable
通过实现runnable接口创建多线程Thread-1
通过实现runnable接口创建多线程Thread-3
通过实现runnable接口创建多线程Thread-0
通过实现runnable接口创建多线程Thread-2
Process finished with exit code 0
- 实现callable接口
package com.orchids.thread.createthread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @ Author qwh
* @ Date 2024/7/27 16:57
*/
//中间的泛型是返回类型
public class implementscallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("通过实现callable接口创建线程");
return "Hello world";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
implementscallable impl = new implementscallable();
FutureTask<String> futureTask = new FutureTask<>(impl);
Thread thread1 = new Thread(futureTask);
Thread thread2 = new Thread(futureTask);
Thread thread3 = new Thread(futureTask);
Thread thread4 = new Thread(futureTask);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
//获取线程返回值
String res = futureTask.get();
System.out.println(res);
}
}
执行结果
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=8436:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.implementscallable
通过实现callable接口创建线程
Hello world
Process finished with exit code 0
结果原因
在Java中,FutureTask是可重入的,但不是可重复执行的。
这意味着多个线程可以尝试执行同一个FutureTask,但是只有第一个调用start()方法的线程能够执行call()方法。一旦call()方法完成执行,其他线程再尝试执行这个FutureTask时,将不会再次执行call()方法,而是立即返回call()方法的结果或者抛出在call()方法中产生的异常。
所以,根据上述代码,只有第一个启动的线程会执行call()方法,其余线程将直接返回结果或异常。具体哪个线程会执行call()方法取决于JVM调度线程的顺序,因此,实际输出结果可能因环境和运行时机而异。
- 实现runnable接口和callable接口的区别
- Runnable接口run方法没有返回值
- Callable接口call方法有返回值是一个泛型和futrue feturetask配合可以用来获取异步执行的结果
- Callable接口支持返回执行结果 需要调用futuretask.get()得到 此方法会阻塞进程的继续往下执行 如果不调用不会阻塞
- Callable接口的call方法允许方法抛出异常
- Runnable接口的run方法的异常只能内部消化不能向上抛
- Callable任务可以被取消,而Runnable任务一旦启动就没有直接的方法取消(除非使用Thread.interrupt())。
- 创建线程池
package com.orchids.thread.createthread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
/**
* @ Author qwh
* @ Date 2024/7/27 17:18
*/
public class UseExecutorsService implements Runnable{
@Override
public void run() {
System.out.println("通过创建线程池创建多线程"+Thread.currentThread().getName());
}
/**
* 程序的入口点。
* 创建一个ForkJoinPool线程池并提交一个UseExecutorsService任务。
* 使用ForkJoinPool是因为它适用于递归任务和并行计算,这里假设UseExecutorsService中包含这类计算。
* 主要目的是展示如何使用ExecutorService来执行任务。
*
* @param args 命令行参数,本程序中未使用。
*/
public static void main(String[] args) {
// 创建UseExecutorsService实例,该实例包含要执行的任务。
UseExecutorsService ues = new UseExecutorsService();
// 创建一个具有4个工作线程的ForkJoinPool。
// ForkJoinPool适用于需要递归处理的任务,这里假设UseExecutorsService适合这种处理方式。
ExecutorService poll = new ForkJoinPool(4);
// 提交UseExecutorsService实例作为任务执行。
// 任务将在这个线程池中异步执行。
poll.submit(ues);
// 关闭线程池,确保所有提交的任务执行完毕后,程序能够安全退出。
// 注意:在实际应用中,应根据任务特性和需求选择合适的关闭策略。
poll.shutdown();
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=8694:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.UseExecutorsService
通过创建线程池创建多线程ForkJoinPool-1-worker-1
Process finished with exit code 0
run start 区别
- start() 方法
当你创建了一个 Thread 对象并调用其 start() 方法时,一个新的线程将被启动。
start() 方法内部会调用 Thread 对象的 run() 方法,但是是在一个新的线程中执行的。
这意味着调用 start() 后,你的新线程将在其自己的线程栈上执行 run() 方法,而不会阻塞调用它的线程。
start() 方法只能被调用一次,否则会抛出 IllegalThreadStateException 异常。
- run() 方法
run() 方法是 Thread 类中的一个普通方法,它包含线程要执行的代码。
直接调用 run() 方法并不会启动一个新的线程,而是会在当前调用它的线程中执行 run() 方法的代码。
这意味着如果你在一个线程中直接调用另一个线程对象的 run() 方法,那么这个方法的执行仍然在原线程中进行,没有实现真正的多线程并发
- start: 用来启动线程 通过线程调用run方法执行run方法中所定义的代码逻辑 start方法只能被调用一次
- run: 封装了要被线程执行的代码 可以被调用多次
线程有那些状态
public enum State {
//尚未启动的线程的线程状态
NEW,
//可运行线程的线程状态。
//处于可运行状态的线程正在Java虚拟机中执行,
//但它可能正在等待来自操作系统(如处理器)的其他资源
RUNNABLE,
//等待监视器锁的线程的线程状态。
//处于阻塞状态的线程正在等待监视器锁进入同步块方法或
//在调用Object.wait后重新进入同步块方法。
BLOCKED,
//等待线程的线程状态。
//由于调用了以下方法之一,
//线程处于等待状态:
//没有超时等待线程。
//无超时连接。
//处于等待状态的线程正在等待另一个线程执行特定的操作。
//例如,在一个对象上调用object. wait()的线程正在等待另一个线程在该对象上调用object. notify()或object. notifyall()。
//调用thread .join()的线程正在等待指定的线程终止
WAITING,
//指定等待时间的等待线程的线程状态。
//线程处于定时等待状态,原因是调用了下列方法之一,并指定了正等待时间:
//睡眠对象。
//等待超时线程。join with timeout LockSupport。parkNanos LockSupport.parkUntil
TIMED_WAITING,
//终止线程的线程状态。线程已完成执行。
TERMINATED;
}
线程状态之间是如何变化的
- NEW (新建)
线程对象刚刚被创建,但尚未启动。
调用 start() 方法后,线程从 NEW 状态变为 RUNNABLE 状态。
- RUNNABLE
线程处于可运行状态,这意味着它可以被调度器选中以运行。
线程可能正在运行,也可能正在等待 CPU 时间片。
从 NEW 状态转换而来,或者从 BLOCKED、WAITING 或 TIMED_WAITING 状态转换而来。
- BLOCKED (阻塞)
线程正在等待监视器锁(即同步锁)以便进入同步块或方法。
当线程试图获取一个已经被其他线程持有的锁时,它会进入 BLOCKED 状态。
当锁被释放时,线程可以重新变为 RUNNABLE 状态。
- WAITING
线程进入了等待状态,等待其他线程的动作。
例如,调用 Object.wait()、Thread.join() 或者 LockSupport.park() 等方法会导致线程进入 WAITING 状态。
线程将一直等待,直到被另一个线程唤醒或中断。
- TIMED_WAITING
线程进入了有限期的等待状态,等待特定的时间段。
例如,调用 Thread.sleep(long millis) 或者 Object.wait(long timeout) 方法会导致线程进入 TIMED_WAITING 状态。
线程将在指定的时间之后自动变为 RUNNABLE 状态,或者被中断。
- TERMINATED (终止)
线程已经执行完毕或因异常而结束。
线程一旦终止,就不能再次被启动。
创建三个线程如何让保证他们按顺序执行
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 18:03
*/
public class ThreeThreadOrder{
public static void main(String[] args) {
Thread T1 = new Thread(){
@Override
public void run() {
System.out.println("线程一"+Thread.currentThread().getName());
}
};
Thread T2 = new Thread(){
@Override
public void run() {
try {
T1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程二"+Thread.currentThread().getName());
}
};
Thread T3 = new Thread(){
@Override
public void run() {
try {
T2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程三"+Thread.currentThread().getName());
}
};
T1.start();
T2.start();
T3.start();
}
}
notify() notifyAll()区别
- notify() 随机唤醒只能唤醒一个wait线程
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 19:52
*/
public class WaitNotify {
static Object lock = new Object();
static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock){
while (!flag){
System.out.println(Thread.currentThread().getName()+"...wating...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...flag is true");
}
});
Thread t2 = new Thread(() -> {
synchronized (lock){
while (!flag){
System.out.println(Thread.currentThread().getName()+"...wating...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...flag is true");
}
});
Thread t3 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " hold lock");
lock.notify();
flag = true;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t3.start();
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=14740:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.WaitNotify
Thread-0...wating...
Thread-2 hold lock
Thread-1...flag is true
Thread-0...flag is true
Process finished with exit code 0
- notifyall()唤醒所有wait线程
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 19:52
*/
public class WaitNotifyAll {
static Object lock = new Object();
static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
while (!flag) {
System.out.println(Thread.currentThread().getName() + "...wating...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "...flag is true");
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
while (!flag) {
System.out.println(Thread.currentThread().getName() + "...wating...");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "...flag is true");
}
});
Thread t3 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " hold lock");
lock.notifyAll();
flag = true;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t3.start();
}
}
notify()
notify()方法随机唤醒一个在该对象监视器上等待的线程。
只有当持有对象锁的线程调用notify()时,等待池中的一条线程才有机会被选中并进入就绪状态,然后有机会获得锁并继续执行。
如果有多个线程在等待,具体哪个线程被唤醒由JVM决定,通常是基于线程优先级和调度策略。
使用notify()时,你需要确保逻辑上只需要一个等待的线程被唤醒,否则可能导致其他需要被唤醒的线程继续等待。
notifyAll()
notifyAll()方法唤醒所有在该对象监视器上等待的线程。
当调用notifyAll()时,所有等待的线程都将从等待状态变为就绪状态,然后它们将竞争对象锁。
这意味着所有等待的线程都有机会继续执行,但一次只有一个线程能获得锁并执行同步代码块。
使用notifyAll()通常在需要唤醒所有等待线程的情况下使用,比如数据更新后所有等待数据的线程都需要检查更新
wait() sheep()的不同
-
所属类不同
- sleep是Thread类的一个静态方法 用于暂停当前正在执行的线程 给其他线程让出cpu时间 主要用于线程的延时或节拍控制
- wait是object的一个实例方法 用于线程间通信 使得线程可以释放对象锁并等待某个条件成立 通常用于同步和线程间协作
-
锁的释放
- sleep在指定的时间结束后线程将继续执行并且在此期间线程不会释放任何锁 如果线程在调用sleep时持有一个或多个锁他会继续持有这些锁
- wait会释放调用该方法的锁直到notify 或nitifyall信号或者其他线程 线程才重新尝试获取锁并继续执行
-
醒来机制
- sleep(long)和wait(long) 的线程都会在等待相应毫秒后醒来
- wait(long) 和wait()话可以被notify唤醒wait不唤醒就会一直等下去
- 都可以打断唤醒
-
锁的特性不同
- wait方法的调用必须获取wait对象的锁 而sleep则无需限制
- wait方法执行后会释放对象锁 允许其他线程获得该对象
- sleep如果在syschronized 代码块中执行并不会释放对象锁
让一个正在运行的线程停止
- 使用退出标志
- 使用stop方法强行终止
- 使用interrupt方法中断线程
flog
package com.orchids.thread.createthread;
import java.text.SimpleDateFormat;
/**
* @ Author qwh
* @ Date 2024/7/27 20:28
*/
public class ExitThread extends Thread{
volatile boolean flag = false;
/**
* 当线程被激活时,此方法被执行。线程会不断地检查一个标志位,直到标志位为真时才停止运行。
* 此方法的目的是为了让线程在特定条件下保持活跃并执行特定的任务。
* 使用了循环和睡眠来实现线程的周期性活动,以及对中断的处理来确保线程可以在必要时被停止。
*/
@Override
public void run() {
// 当flag为false时,线程将持续执行下面的循环
while(!flag) {
// 打印线程运行的信息
System.out.println("run...now date..."+ new SimpleDateFormat("yyyy-MM-dd:HH:mm:ssss").format(System.currentTimeMillis()));
try {
// 让线程睡眠3秒,以便其他线程可以运行
Thread.sleep(3000);
} catch (InterruptedException e) {
// 如果线程在睡眠时被中断,打印异常信息
e.printStackTrace();
}
}
}
/**
* 程序入口主方法。
* 创建并启动一个ExitThread线程,模拟一个场景:线程执行一段时间后,通过修改标志位来请求线程退出。
* 这里通过Thread.sleep模拟了主线程的等待,以便观察ExitThread线程如何处理退出请求。
* @param args 命令行参数
* @throws InterruptedException 如果主线程在睡眠时被中断
*/
public static void main(String[] args) throws InterruptedException {
// 创建ExitThread线程实例并启动
//这个线程每3秒打印一次时间 但是因为主线程睡了6秒后 执行修改标志位 修改后从线程结束run方法
ExitThread thread = new ExitThread();
thread.start();
// 主线程睡眠6秒,模拟背景操作
Thread.sleep(6000);
// 设置ExitThread的标志位为true,请求线程退出
thread.flag = true;
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=1307:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.ExitThread
run...now date...2024-07-27:20:37:0007
run...now date...2024-07-27:20:37:0010
Process finished with exit code 0
stop
package com.orchids.thread.createthread;
import java.text.SimpleDateFormat;
/**
* @ Author qwh
* @ Date 2024/7/27 20:38
*/
public class ExitThreadInterrupt extends Thread{
volatile boolean flag = false ;
@Override
public void run() {
// 当flag为false时,线程将持续执行下面的循环
while(!flag) {
// 打印线程运行的信息
System.out.println("run...now date..."+ new SimpleDateFormat("yyyy-MM-dd:HH:mm:ssss").format(System.currentTimeMillis()));
try {
// 让线程睡眠3秒,以便其他线程可以运行
Thread.sleep(3000);
} catch (InterruptedException e) {
// 如果线程在睡眠时被中断,打印异常信息
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// 创建ExitThread线程实例并启动
//这个线程每3秒打印一次时间 但是因为主线程睡了6秒后 执行修改标志位 修改后从线程结束run方法
ExitThreadFlag thread = new ExitThreadFlag();
thread.start();
// 主线程睡眠6秒,模拟背景操作
Thread.sleep(6000);
thread.stop();
}
}
interrupt
打断阻塞的线程
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 20:41
*/
public class ExitThreadInterrupt extends Thread{
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
System.out.println("t1 正在运行...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
t1.start();
Thread.sleep(500);
t1.interrupt();
System.out.println(t1.isInterrupted());
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=1380:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.ExitThreadInterrupt
t1 正在运行...
true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.orchids.thread.createthread.ExitThreadInterrupt.lambda$main$0(ExitThreadInterrupt.java:13)
at java.lang.Thread.run(Thread.java:750)
Process finished with exit code 0
打断正常的线程
package com.orchids.thread.createthread;
/**
* @ Author qwh
* @ Date 2024/7/27 20:46
*/
public class ExitThreadInterrupt1 {
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(()->{
while(true) {
Thread current = Thread.currentThread();
boolean interrupted = current.isInterrupted();
if(interrupted) {
System.out.println("打断状态:"+interrupted);
break;
}
}
}, "t2");
t2.start();
Thread.sleep(500);
t2.interrupt();
}
}
打断状态:true
Process finished with exit code 0
syschronized 底层原理
- 字节码插入:当编译器遇到synchronized关键字时,会在字节码中插入monitorenter和monitorexit指令,分别对应获取锁和释放锁的操作。
- 锁的获取与释放:monitorenter指令会尝试获取对象的锁。如果锁是可用的,那么当前线程将持有该锁,并且锁状态会改变。monitorexit指令用于释放锁。
- 锁的升级:为了提高性能,JVM实现了锁的升级机制,包括无锁状态、偏向锁、轻量级锁和重量级锁。这些锁状态之间的转换是为了减少锁的获取和释放带来的开销。
- 锁的撤销:如果线程在持有锁期间被中断或抛出异常,锁会被自动释放,以防止死锁的发生。
乐观锁 悲观锁
- 悲观锁(Pessimistic Locking)
悲观锁基于一个“悲观”的假设,即认为数据非常有可能被并发的事务所修改,因此在事务开始时就对数据进行锁定,直到事务结束。这样可以避免数据在事务执行过程中被其他事务修改。悲观锁通常在数据库系统中实现,例如使用行级锁或表级锁。在数据库中,SELECT … FOR UPDATE语句就是一个悲观锁的应用实例,它确保了在事务执行期间,其他事务无法修改被锁定的数据行。
- 乐观锁(Optimistic Locking)
乐观锁基于一个“乐观”的假设,即认为数据不太可能在事务执行期间被修改。因此,乐观锁不会在事务开始时锁定数据,而是在事务提交时检查数据是否被其他事务修改过。这通常是通过在数据表中增加一个版本字段(version)或时间戳字段(timestamp)来实现的。每次数据更新时,版本号也会随之递增。当事务提交时,它会检查数据的版本号是否与开始时相同,如果不同,则表示数据已被其他事务修改,此时事务将回滚,否则事务正常提交
- CAS CompareAndSwap 基于乐观锁思想
- synchronization 基于悲观锁思想
volatile
- volatile是Java中的一个关键字,主要用于变量的声明,它提供了内存可见性和禁止指令重排序两个关键特性,常用于多线程环境下保证变量的可见性和防止某些特定类型的优化
- 内存可见性
在多线程环境中,每个线程都有自己的工作内存,线程在执行时会从主内存中复制一份变量到自己的工作内存中,然后在自己的工作内存中进行操作,最后再把结果写回到主内存中。这种机制虽然提高了效率,但也带来了线程间数据不一致的问题。volatile关键字可以确保当一个线程修改了一个volatile变量后,这个修改会立即反映到主内存中,其他线程读取这个变量时,会从主内存中读取最新的值,从而保证了变量的可见性
- 禁止指令重排序
在编译器和处理器中,为了提高性能,可能会对指令进行重排序。volatile关键字可以禁止某些类型的指令重排序,确保程序按照代码的顺序执行,这对于多线程程序来说是非常重要的,因为指令重排序可能会导致多线程程序的行为不符合预期
synchronized lock区别
- synchronized
语法糖:synchronized是Java语言内置的关键字,使用起来更加简单直观,不需要显式地去获取和释放锁。
自动释放锁:当线程执行完synchronized代码块或方法后,锁会自动释放,不需要显式地调用解锁方法。
异常处理:如果在synchronized代码块中发生异常,锁会自动释放,避免了死锁的风险。
锁粒度:synchronized可以应用于代码块或方法,作用于当前对象或类的所有实例。
性能问题:早期的JVM实现中,synchronized的性能较差,因为它采用了重量级的锁实现。但从Java 6开始,JVM对synchronized进行了大量优化,引入了偏向锁、轻量级锁和重量级锁的概念,大大提高了其性能。
- Lock接口
显式控制:Lock接口是Java并发包java.util.concurrent.locks的一部分,需要显式地调用lock()方法获取锁,以及unlock()方法释放锁。
更细粒度的控制:Lock接口提供了更高的灵活性,例如可重入锁、公平锁、非公平锁、定时锁等待等。
异常处理:如果在使用Lock时发生异常,锁不会自动释放,必须在finally块中调用unlock()方法来确保锁被释放,否则可能导致死锁。
可中断的等待:Lock接口提供了tryLock()方法,可以尝试获取锁而不立即阻塞,或者在指定时间内等待锁。
性能:在某些情况下,Lock接口可以提供更好的性能,尤其是当需要更复杂的锁行为时。
死锁产生的条件
- 一个线程同时获取多把锁
线程一 获得A锁 接下来获取B锁
线程二 获得B锁接下来获取A锁
package com.orchids.thread.createthread;
import static java.lang.Thread.sleep;
/**
* @ Author qwh
* @ Date 2024/7/27 21:18
*/
public class DeathLock {
public static void main(String[] args) throws InterruptedException {
Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized (A) {
System.out.println(Thread.currentThread().getName()+"获取到了 A锁");
System.out.println(Thread.currentThread().getName()+"接下来去获取 B锁");
try {
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (B) {
System.out.println("获取锁 B锁");
System.out.println("操作...");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (B) {
System.out.println(Thread.currentThread().getName()+"获取到了 B锁");
System.out.println(Thread.currentThread().getName()+"接下来去获取 B锁");
try {
sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (A) {
System.out.println("获取锁 A");
System.out.println("操作...");
}
}
});
t1.start();
t2.start();
}
}
D:\Java\jdk1.8.0_333\bin\java.exe "-javaagent:D:\IntelliJ IDEA 2023.3.6\lib\idea_rt.jar=1896:D:\IntelliJ IDEA 2023.3.6\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8.0_333\jre\lib\charsets.jar;D:\java\jdk1.8.0_333\jre\lib\deploy.jar;D:\java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;D:\java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8.0_333\jre\lib\ext\localedata.jar;D:\java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunec.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;D:\java\jdk1.8.0_333\jre\lib\javaws.jar;D:\java\jdk1.8.0_333\jre\lib\jce.jar;D:\java\jdk1.8.0_333\jre\lib\jfr.jar;D:\java\jdk1.8.0_333\jre\lib\jfxswt.jar;D:\java\jdk1.8.0_333\jre\lib\jsse.jar;D:\java\jdk1.8.0_333\jre\lib\management-agent.jar;D:\java\jdk1.8.0_333\jre\lib\plugin.jar;D:\java\jdk1.8.0_333\jre\lib\resources.jar;D:\java\jdk1.8.0_333\jre\lib\rt.jar;F:\IDEA\meeting\target\classes;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.1\junit-jupiter-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.1\junit-jupiter-api-5.8.1.jar;F:\Maven\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-commons\1.8.1\junit-platform-commons-1.8.1.jar;F:\Maven\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.1\junit-jupiter-params-5.8.1.jar;F:\Maven\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.1\junit-jupiter-engine-5.8.1.jar;F:\Maven\.m2\repository\org\junit\platform\junit-platform-engine\1.8.1\junit-platform-engine-1.8.1.jar com.orchids.thread.createthread.DeathLock
Thread-0获取到了 A锁
Thread-0接下来去获取 B锁
Thread-1获取到了 B锁
Thread-1接下来去获取 A锁
Process finished with exit code 130
死锁诊断
- jps
线程池 核心参数
/**
* 创建一个具有可调整线程池大小的执行器。
*
* 此构造函数允许详细配置线程池的各种属性,包括核心线程数、最大线程数、线程保持活动时间、时间单位、任务队列和拒绝执行处理器。
* 这些配置选项使得ThreadPoolExecutor能够灵活适应不同的并发需求。
*
* @param corePoolSize 核心线程数,即始终维持的最小线程数。
* @param maximumPoolSize 最大线程数,线程池允许的最大并发线程数。
* @param keepAliveTime 空闲线程的存活时间。
* @param unit 存活时间的时间单位。
* @param workQueue 用于保存任务的队列,当线程池达到最大线程数时,新任务将被放入此队列。
* @param threadFactory 用于创建新线程的工厂。
* @param handler 当提交的任务无法被线程池接受时,用于处理拒绝执行情况的处理器。
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
- 任务提交 判断核心线程数是否已满 如果没有没有满则添加到工作线程执行
- 如果核心线程数满了 判断阻塞队列是否已满 如果没有当前任务存入阻塞队列
- 如果阻塞队列也满了,则判断线程数是否小于最大线程数,如果满足条件,则使用临时线程执行任务
- 如果核心或临时线程执行完成任务后会检查阻塞队列中是否有需要执行的线程,如果有,则使用非核心线程执行任务
- 如果所有线程都在忙着(核心线程+临时线程),则走拒绝策略