当前位置:网站首页>线程常用方法与守护线程
线程常用方法与守护线程
2022-07-01 03:28:00 【兀坐晴窗独饮茶】
常用方法
| 方法名 | static | 功能说明 | 注意 |
|---|---|---|---|
| start() | 启动一个新线程,在新的线程运行 run 方法中的代码 | start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException | |
| run() | 新线程启动后会调用的方法 | 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为 | |
| join() | 等待线程运行结束 | ||
| join(long n) | 等待线程运行结束,最多等待 n 毫秒 | ||
| getId() | 获取线程长整型的 id | id 唯一 | |
| getName() | 获取线程名 | ||
| setName(String) | 修改线程名 | ||
| getPriority() | 获取线程优先级 | ||
| setPriority(int) | 修改线程优先级 | java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率 | |
| getState() | 获取线程状态 | Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED | |
| isInterrupted() | 判断是否被打断 | 不会清除 打断标记 | |
| isAlive() | 线程是否存活(还没有运行完毕) | ||
| interrupt() | 打断线程 | 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛InterruptedException,并清除打断标记;如果打断的正在运行的线程,则会设置 打断标记;park 的线程被打断,也会设置打断标记 | |
| interrupted() | static | 判断当前线程是否被打断 | 会清除 打断标记 |
| currentThread() | static | 获取当前正在执行的线程 | |
| sleep(long n) | static | static让当前执行的线程休眠n毫秒,休眠时让出 cpu的时间片给其它线程 | |
| yield() | static | 提示线程调度器让出当前线程对CPU的使用 | 主要是为了测试和调试 |
start 与 run
start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException
测试代码 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.io.FileReader;
/** * @author 王天赐 * @title: TestStartAndRun * @projectName hm-juc-codes * @description: 测试start与run方法 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-21 15:13 */
@Slf4j(topic = "c.TestStartAndRun")
@SuppressWarnings("all")
public class TestStartAndRun {
/** * 模拟读取 */
public static void reader() {
long start = System.currentTimeMillis();
int sum = 0;
for (int i = 0; i < 10000_000_00; i++) {
sum += sum;
}
long end = System.currentTimeMillis();
log.debug("reader cost {} ms ... ", (end - start));
}
public static void main(String[] args) {
Thread t1 = new Thread("t1") {
@Override
public void run() {
// 获取当前线程的名字
log.debug("{} running ... ", Thread.currentThread().getName());
reader();
}
};
t1.start();
log.debug("do other thing ... ");
}
}
运行结果
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=6195:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestStartAndRun
16:07:46.045 [main] DEBUG c.TestStartAndRun - do other thing ...
16:07:46.045 [t1] DEBUG c.TestStartAndRun - t1 running ...
16:07:46.301 [t1] DEBUG c.TestStartAndRun - reader cost 254 ms ...
Process finished with exit code 0
如上面的运行结果所示 :
t1线程开启后并没有立马执行 , 而是执行了主线程的方法, 后再执行的t1线程的方法- 注意
running是 t1线程执行的 ! - t1 线程和主线程是并行执行的 !
而使用 run 执行时, running 是 在 主线程执行的, 并没有新开一个线程!

代码实例 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.TestStartStatus")
@SuppressWarnings("all")
public class TestStartStatus {
public static void main(String[] args) {
Thread t1 = new Thread("t1") {
@Override
public void run() {
// 获取当前线程的名字
log.debug("{} running ... ", Thread.currentThread().getName());
}
};
log.debug("t1 : {} " , t1.getState());
t1.start();
log.debug("t1 : {} " , t1.getState());
}
}
执行结果 :
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=14539:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestStartStatus
17:28:18.600 [main] DEBUG c.TestStartStatus - t1 : NEW
17:28:18.604 [main] DEBUG c.TestStartStatus - t1 : RUNNABLE
17:28:18.604 [t1] DEBUG c.TestStartStatus - t1 running ...
Process finished with exit code 0
可以看到上面的执行结果以及代码 , 当执行 start()方法以后, 线程的状态从 NEW 变成了 RUNNABLE
总结 :
- 直接调用 run 是在主线程中执行了 run,没有启动新的线程
- 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码
sleep 与 yield
sleep
- 调用 sleep 会让当前线程从
Running进入Timed Waiting状态(阻塞) - 当前线程可以使用
interrupt方法打断正在睡眠的线程,这时 sleep 方法会抛出InterruptedException - 睡眠结束后的线程未必会立刻得到执行
- 建议用
TimeUnit的sleep代替Thread的sleep来获得更好的可读性
sleep 状态
代码示例 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.TestSleep")
@SuppressWarnings("all")
public class TestSleep {
public static void main(String[] args){
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("t1 running ... ");
log.debug("into sleep ... ");
// 睡眠的是当前线程
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.debug("t1 wake up ... ");
throw new RuntimeException(e);
}
}
};
log.debug("t1 status is {} ... " , t1.getState());
t1.start();
log.debug("t1 status is {} ... " , t1.getState());
// 打断其他正在睡眠的线程
log.debug("do other things ... ");
}
}
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=6691:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestSleep
20:01:43.076 [main] DEBUG c.TestSleep - t1 status is NEW ...
20:01:43.079 [main] DEBUG c.TestSleep - t1 status is RUNNABLE ...
20:01:43.079 [main] DEBUG c.TestSleep - do other things ...
20:01:43.079 [t1] DEBUG c.TestSleep - t1 running ...
20:01:43.079 [t1] DEBUG c.TestSleep - into sleep ...
Process finished with exit code 0
示例图

让主线程睡眠的原因是因为 防止 t1线程还没有睡眠, t1线程的状态信息已经被打印出来, 此时t1线程的状态依然是 RUNNABLE
sleep 打断
代码示例 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
/** * @author 王天赐 * @title: TestInterceptor * @projectName hm-juc-codes * @description: 测试sleep打断 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-21 20:39 */
@Slf4j(topic = "c.TestSleep")
@SuppressWarnings("all")
public class TestInterceptor {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread("t1") {
@Override
public void run() {
log.debug("t1 running ... ");
// 睡眠的是当前线程
try {
log.debug("start sleep ... ");
Thread.sleep(2000);
} catch (InterruptedException e) {
log.debug("t1 wake up ... ");
throw new RuntimeException(e);
}
}
};
t1.start();
// 主线程睡眠是要保证 t1 线程在执行 interrupt 方法时已经在睡眠
Thread.sleep(1000);
t1.interrupt();
log.debug("do other things ... ");
}
}
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=6365:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestInterceptor
20:51:30.022 [t1] DEBUG c.TestSleep - t1 running ...
20:51:30.024 [t1] DEBUG c.TestSleep - start sleep ...
20:51:31.023 [t1] DEBUG c.TestSleep - t1 wake up ...
20:51:31.023 [main] DEBUG c.TestSleep - do other things ...
Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
at cn.knightzz.example.e2.method.TestInterceptor$1.run(TestInterceptor.java:30)
Caused by: java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.knightzz.example.e2.method.TestInterceptor$1.run(TestInterceptor.java:27)
运行结果如上, 可以看到, t1 线程在休眠1s以后, 就被打断了
TimeUnit Sleep
增加可读性
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.util.concurrent.TimeUnit;
/** * @author 王天赐 * @title: TestUnit * @projectName hm-juc-codes * @description: 测试TimeUnit * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-21 20:59 */
@Slf4j(topic = "c.TestTimeUnit")
@SuppressWarnings("all")
public class TestTimeUnit {
public static void main(String[] args) throws InterruptedException {
log.debug("start ...");
TimeUnit.SECONDS.sleep(10);
// Thread.sleep()
log.debug("end ...");
}
}
yield
- 调用 yield 会让当前线程从
Running进入Runnable就绪状态,然后调度执行其它线程 - 具体的实现依赖于操作系统的任务调度器
- 目的是把当前线程的CPU执行权让出去, 但是CPU下一次可能还会把时间片分给

线程优先级
- 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
- 如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
CPU闲的情况
代码示例 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
/** * @author 王天赐 * @title: TestPriority * @projectName hm-juc-codes * @description: 测试进程优先级 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-22 20:33 */
@SuppressWarnings("all")
@Slf4j(topic = "c.TestPriority")
public class TestPriority {
public static void main(String[] args) {
Runnable task1 = new Runnable() {
@Override
public void run() {
log.debug("task1 running ... ");
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
log.debug("task2 running ... ");
}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t1");
// 设置优先级
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
log.debug("main ended ... ");
}
}
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=8641:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestPriority
20:38:32.626 [main] DEBUG c.TestPriority - main ended ...
20:38:32.626 [t1] DEBUG c.TestPriority - task2 running ...
20:38:32.626 [t1] DEBUG c.TestPriority - task1 running ...
Process finished with exit code 0
可以看到 , 上面的运行结果 : 尽管 t1线程设置了最大的优先级, 但是仍然会出现t2线程先运行的情况
CPU繁忙的情况
但是 如果 线程繁忙的时候 :
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
/** * @author 王天赐 * @title: TestPriority * @projectName hm-juc-codes * @description: 测试进程优先级 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-22 20:33 */
@SuppressWarnings("all")
@Slf4j(topic = "c.TestPriority")
public class TestPriority {
public static void main(String[] args) {
Runnable task1 = new Runnable() {
@Override
public void run() {
// log.debug("task1 running ... ");
int count = 0;
while (true) {
Thread.yield();
log.debug("task1 ==================> {}", count);
count++;
}
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
int count = 0;
while (true) {
Thread.yield();
log.debug("task2 ==================> {}", count);
count++;
}
}
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t1");
// 设置优先级
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
log.debug("main ended ... ");
}
}

如上图可以看到 , task1 的数字要比 task2 的数字大, 说明task1获取CPU时间片的次数比较多
join 方法详解
join 方法的作用的等待对应线程结束, 比如 t1.join() 作用是等待t1线程结束
案例 1 一般情况
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestJoin")
public class TestJoin {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
method1();
}
private static void method1() throws InterruptedException {
log.debug("method1 start ... ");
Thread t1 = new Thread(() -> {
try {
log.debug("sleep start ... ");
TimeUnit.SECONDS.sleep(1);
value = 10;
log.debug("sleep end ... ");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t1.start();
log.debug("value 结果 {} ", value);
log.debug("main end ... ");
}
}
C:\dev\Java\jdk1.8.0_152\bin\java.exe -javaagent:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=5463:D:\DevApp\JetBrain\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\dev\Java\jdk1.8.0_152\jre\lib\charsets.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\deploy.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\dnsns.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jaccess.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\localedata.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\nashorn.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunec.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\ext\zipfs.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\javaws.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jce.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfr.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jfxswt.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\jsse.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\management-agent.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\plugin.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\resources.jar;C:\dev\Java\jdk1.8.0_152\jre\lib\rt.jar;F:\JavaCode\hm-juc-codes\juc-case-01\target\classes;F:\MavenRepo\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;F:\MavenRepo\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;F:\MavenRepo\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;F:\MavenRepo\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;F:\MavenRepo\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;F:\MavenRepo\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;F:\MavenRepo\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;F:\MavenRepo\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;F:\MavenRepo\org\openjdk\jmh\jmh-java-benchmark-archetype\1.35\jmh-java-benchmark-archetype-1.35.jar cn.knightzz.example.e2.method.TestJoin
21:56:45.562 [main] DEBUG c.TestJoin - method1 start ...
21:56:45.594 [Thread-0] DEBUG c.TestJoin - sleep start ...
21:56:45.594 [main] DEBUG c.TestJoin - value 结果 0
21:56:45.595 [main] DEBUG c.TestJoin - main end ...
21:56:46.606 [Thread-0] DEBUG c.TestJoin - sleep end ...
Process finished with exit code 0
可以看到上面的结果, 输出的value值是 0, 这是因为主线程和t1线程是并行执行的, 不存在谁等谁的情况

案例 2 join
我们可以使用 join 来等待线程结束
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestJoin")
public class TestJoin {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
method1();
}
private static void method1() throws InterruptedException {
log.debug("method1 start ... ");
Thread t1 = new Thread(() -> {
try {
log.debug("sleep start ... ");
TimeUnit.SECONDS.sleep(1);
value = 10;
log.debug("sleep end ... ");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t1.start();
t1.join();
log.debug("value 结果 {} ", value);
log.debug("main end ... ");
}
}

从调用方的角度 :
- 需要等待结果返回, 才能继续执行的是 同步
- 不需要等待结果返回就可以继续执行的是 异步
案例3 join方法
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestJoin2")
public class TestJoin2 {
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
try {
// 睡眠 1s
TimeUnit.SECONDS.sleep(1);
// 修改 value 的值
value = 10;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
try {
// 睡眠 1s
TimeUnit.SECONDS.sleep(2);
// 修改 value 的值
value = 20;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("value : {} " , value);
log.debug("do other thing ... ");
}
}
问 : 上面的代码执行时间是 3s 还是 2s ?

案例4 有时效的join
我们可以通过指定传入参数指定等待的时间 : t1.join(3000);
package cn.knightzz.example.e2.method;
import cn.knightzz.example.e1.test.Test2;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestJoin2")
public class TestJoin3 {
static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
// 睡眠 5s
try {
TimeUnit.SECONDS.sleep(5);
value = 10;
log.debug("sleep end ... ");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
t1.start();
log.debug("thread start ... ");
t1.join(3000);
log.debug("value : {}", value);
log.debug("join end ... ");
}
}
C:\Dev\jdk8\bin\java.exe -javaagent:D:\DevApp\JetBrains\ToolBox\apps\IDEA-U\ch-0\221.5787.30\lib\idea_rt.jar=4754:D:\DevApp\JetBrains\ToolBox\apps\IDEA-U\ch-0\221.5787.30\bin -Dfile.encoding=UTF-8 -classpath C:\Dev\jdk8\jre\lib\charsets.jar;C:\Dev\jdk8\jre\lib\ext\access-bridge-64.jar;C:\Dev\jdk8\jre\lib\ext\cldrdata.jar;C:\Dev\jdk8\jre\lib\ext\dnsns.jar;C:\Dev\jdk8\jre\lib\ext\dtfj.jar;C:\Dev\jdk8\jre\lib\ext\dtfjview.jar;C:\Dev\jdk8\jre\lib\ext\jaccess.jar;C:\Dev\jdk8\jre\lib\ext\localedata.jar;C:\Dev\jdk8\jre\lib\ext\nashorn.jar;C:\Dev\jdk8\jre\lib\ext\sunec.jar;C:\Dev\jdk8\jre\lib\ext\sunjce_provider.jar;C:\Dev\jdk8\jre\lib\ext\sunmscapi.jar;C:\Dev\jdk8\jre\lib\ext\sunpkcs11.jar;C:\Dev\jdk8\jre\lib\ext\traceformat.jar;C:\Dev\jdk8\jre\lib\ext\zipfs.jar;C:\Dev\jdk8\jre\lib\jce.jar;C:\Dev\jdk8\jre\lib\jsse.jar;C:\Dev\jdk8\jre\lib\management-agent.jar;C:\Dev\jdk8\jre\lib\resources.jar;C:\Dev\jdk8\jre\lib\rt.jar;C:\Dev\jdk8\bin\Dll02.dll;K:\CodeSpace\HMCodeSpace\hm-juc-codes\juc-case-01\target\classes;D:\Repos\mavenRepos\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;D:\Repos\mavenRepos\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;D:\Repos\mavenRepos\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;D:\Repos\mavenRepos\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;D:\Repos\mavenRepos\cn\hutool\hutool-all\5.7.20\hutool-all-5.7.20.jar;D:\Repos\mavenRepos\org\openjdk\jmh\jmh-core-benchmarks\1.35\jmh-core-benchmarks-1.35.jar;D:\Repos\mavenRepos\org\openjdk\jmh\jmh-core\1.35\jmh-core-1.35.jar;D:\Repos\mavenRepos\net\sf\jopt-simple\jopt-simple\5.0.4\jopt-simple-5.0.4.jar;D:\Repos\mavenRepos\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar cn.knightzz.example.e2.method.TestJoin3
21:16:55.011 [main] DEBUG c.TestJoin2 - thread start ...
21:16:58.017 [main] DEBUG c.TestJoin2 - value : 0
21:16:58.019 [main] DEBUG c.TestJoin2 - join end ...
21:17:00.015 [Thread-3] DEBUG c.TestJoin2 - sleep end ...
Process finished with exit code 0
如上面可以看到
interrupt 方法详解
打断sleep, wait, join 的线程
sleep, wait, join这几个方法都会让线程进入阻塞状态 , 打断 sleep 的线程, 会清空打断状态(打断状态会重置为 false ),以 sleep 为例
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/** * @author 王天赐 * @title: TestInterrupt * @projectName hm-juc-codes * @description: 打断sleep线程 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-27 21:37 */
@SuppressWarnings("all")
@Slf4j(topic = "c.TestInterrupt")
public class TestInterrupt {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(5); // sleep, wait, join 被打断后, 打断标记会被清空
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "t1");
t1.start();
// 主线程睡眠1s , 保证打断时, t1线程已经sleep
TimeUnit.SECONDS.sleep(1);
// 打断
t1.interrupt();
// 查看打断状态
log.debug("打断标记 : {}" , t1.isInterrupted());
}
}

如上图可以看到 , t1 线程在睡眠中被打断, 并且打断标记被重新设置为 false
t1.isInterrupted() 如果线程已经被打断返回 true, 否则返回 false, 睡眠中被打断的线程会抛出异常的
打断正常的线程
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/** * @author 王天赐 * @title: TestInterrupt2 * @projectName hm-juc-codes * @description: 测试打断正常线程 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-06-28 14:45 */
@SuppressWarnings("all")
@Slf4j(topic = "c.TestInterrupt2")
public class TestInterrupt2 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while(true) {
Thread thread = Thread.currentThread();
boolean interrupted = thread.isInterrupted();
if (interrupted) {
log.debug("打断状态 : {} " , interrupted);
break;
}
}
}, "t1");
t1.start();
// 休眠一秒, 保证t1线程处于运行状态
TimeUnit.SECONDS.sleep(1);
t1.interrupt();
}
}

如上图可以看到 : 正常线程运行时被打断, 此时打断状态是 true
模式之两阶段终止
问题
- 在线程t1里面正确的打断线程t2 , 并且让t2线程有一个可以处理被打断后的方法
错误思路
使用线程对象的 stop() 方法停止线程
stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁, 其它线程将永远无法获取锁
使用 System.exit(int) 方法停止线程
- 目的仅是停止一个线程,但这种做法会让整个程序都停止
两阶段终止模式
https://blog.csdn.net/thetimelyrain/article/details/114587111
LockSupport.park()可以让当前线程阻塞
package cn.knightzz.example.e2.method;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestInterrupt2")
public class TestPark {
public static void main(String[] args) throws InterruptedException {
method1();
}
private static void method1() throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("thread park ... ");
LockSupport.park(); // 暂停当前线程
log.debug("thread unpark ... ");
log.debug("打断状态 : {} " , Thread.currentThread().isInterrupted());
}, "t1");
t1.start();
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
// 打断 t1 线程的park
t1.interrupt();
}
}

可以看到上面的运行结果 , 主线程休眠 1s 以后, 开始打断
LockSupport.park(); 方法细节 :
- 第一次执行park被打断以后, isInterrupted 会变为 true
- 此时, 如果再次调用 park() 方法就无法阻塞线程了.
private static void method1() throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("thread park ... ");
LockSupport.park(); // 暂停当前线程
log.debug("thread unpark ... ");
log.debug("打断状态 : {} " , Thread.currentThread().isInterrupted());
// park() 方法细节 :
// 1. 第一次执行park被打断以后, isInterrupted 会变为 true
// 2. 此时, 如果再次调用 park() 方法就无法阻塞线程了.
LockSupport.park();
log.debug("thread unpark ... ");
}, "t1");
t1.start();
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
// 打断 t1 线程的park
t1.interrupt();
}

如上图可以看到, 当打断线程后, 再次调用 park 方法无法阻塞线程
- 可以使用 Thread.interrupted() 清除打断状态
private static void method1() throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("thread park ... ");
LockSupport.park(); // 暂停当前线程
log.debug("thread unpark ... ");
log.debug("打断状态 : {} " , Thread.currentThread().isInterrupted());
// park() 方法细节 :
// 1. 第一次执行park被打断以后, isInterrupted 会变为 true
// 2. 此时, 如果再次调用 park() 方法就无法阻塞线程了.
LockSupport.park();
log.debug("thread unpark ... ");
// 清除打断状态
log.debug("clear interrupt status ... ");
Thread.currentThread().interrupted();
log.debug("thread park ... ");
LockSupport.park();
log.debug("thread unpark ... ");
}, "t1");
t1.start();
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
// 打断 t1 线程的park
t1.interrupt();
}

如上图可以看到 , 在清除打断状态以后, 重新调用 park() 方法, 此时 线程被阻塞
LockSupport.park 总结
LockSupport.park()用来阻塞当前线程, 并且可以被interrupt()方法打断- 第一次执行park被打断以后, isInterrupted 会变为 true
- 此时, 如果再次调用 park() 方法就无法阻塞线程了.
- 但是我们可以调用
Thread.currentThread().interrupted();清除线程打断状态
不推荐使用方法
不推荐使用的方法,这些方法已过时,容易破坏同步代码块,造成线程死锁 :
- stop() 停止线程运行
- suspend() 挂起(暂停)线程运行
- resume() 恢复线程运行
主线程与守护线程
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
package cn.knightzz.example.e2.thread;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestDaemon")
public class TestDaemon {
public static void main(String[] args) throws InterruptedException {
method1();
TimeUnit.SECONDS.sleep(1);
log.debug("main end ... ");
}
private static void method1() {
Thread t1 = new Thread(() -> {
log.debug("thread start ... ");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.debug("thread end ... ");
}, "t1");
// 设置当前线程为守护线程
// 做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束
t1.setDaemon(true);
t1.start();
}
}

如上图, 根据上面的代码 当t1线程启动后 休眠3s 才会执行结束, 但是由于 t1 线程被设置为守护线程, 所以
当main方法结束后, 即使 t1线程并未执行结束, 但是也被强制关闭
边栏推荐
- Future of NTF and trends in 2022
- How to display scrollbars on the right side of the background system and how to solve the problem of double scrollbars
- Quickly filter data such as clock in time and date: Excel filter to find whether a certain time point is within a certain time period
- [TA frost wolf \u may- hundred people plan] 1.2.1 vector basis
- Promql select time series
- TEC: Knowledge Graph Embedding with Triple Context
- 8. string conversion integer (ATOI)
- 10. regular expression matching
- 30. Concatenate substrings of all words
- Gorilla/mux framework (RK boot): RPC error code design
猜你喜欢

SEM of C language_ Tvariable type

【TA-霜狼_may-《百人计划》】1.2.3 MVP矩阵运算

AfxMessageBox和MessageBox的用法

431. 将 N 叉树编码为二叉树 DFS
![[ta- frost wolf \u may- hundred people plan] 1.1 rendering pipeline](/img/af/4498382bc47d8c9ae41c407b9d1265.png)
[ta- frost wolf \u may- hundred people plan] 1.1 rendering pipeline

How to display scrollbars on the right side of the background system and how to solve the problem of double scrollbars

Use selenium automated test tool to climb the enrollment score line and ranking of colleges and universities related to the college entrance examination

[TA frost wolf \u may - "hundred people plan"] 2.1 color space

Pytorch training deep learning network settings CUDA specified GPU visible

Test function in pychram
随机推荐
How to display scrollbars on the right side of the background system and how to solve the problem of double scrollbars
【TA-霜狼_may-《百人计划》】2.2 模型与材质空间
【TA-霜狼_may-《百人計劃》】2.3 常用函數介紹
pytorch nn. AdaptiveAvgPool2d(1)
171. Excel 表列序号
Addition without addition, subtraction, multiplication and division
Processing of menu buttons on the left and contents on the right of the background system page, and double scrolling appears on the background system page
Binary tree god level traversal: Morris traversal
报错:Plug-ins declaring extensions or extension points must set the singleton directive to true
idea插件备份表
The difference between MFC for static libraries and MFC for shared libraries
Unexpected token o in JSON at position 1, JSON parsing problem
Database DDL (data definition language) knowledge points
【TA-霜狼_may-《百人计划》】2.1 色彩空间
详解Spark运行模式(local+standalone+yarn)
All in one 1086: Jiaogu conjecture
318. 最大单词长度乘积
242. valid Letter heteronyms
Use of comment keyword in database
Promql select time series