| 方法名 | 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 方法只是让线程进入就绪,里面代码不一定立刻运行(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线程执行的 !而使用 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
总结 :
Running 进入 Timed Waiting 状态(阻塞)interrupt方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedExceptionTimeUnit 的 sleep 代替 Thread 的 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
代码示例 :
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以后, 就被打断了
增加可读性
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 ...");
}
}
Running进入 Runnable就绪状态,然后调度执行其它线程
代码示例 :
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线程先运行的情况
但是 如果 线程繁忙的时候 :
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 方法的作用的等待对应线程结束, 比如 t1.join() 作用是等待t1线程结束
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线程是并行执行的, 不存在谁等谁的情况

我们可以使用 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 ... ");
}
}

从调用方的角度 :
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 ?

我们可以通过指定传入参数指定等待的时间 : 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
如上面可以看到
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
使用线程对象的 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(); 方法细节 :
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 方法无法阻塞线程
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() 用来阻塞当前线程, 并且可以被 interrupt() 方法打断 Thread.currentThread().interrupted(); 清除线程打断状态不推荐使用的方法,这些方法已过时,容易破坏同步代码块,造成线程死锁 :
默认情况下,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线程并未执行结束, 但是也被强制关闭