一、常用方法
方法 | 说明 |
---|---|
start() | 启动一个新线程,每个线程只能调用一次 |
run() | 新线程启动后会调用的方法 |
join() | 等待线程结束 |
getId() | 获取线程唯一ID |
get/setName() | 获取/修改线程名 |
get/setPriority() | 获取/修改线程优先级 |
getState() | 获取线程状态 |
isAlive() | 判断是否存活 |
interrupt() | 打断线程,设置打断标记为true |
interrupted | 判断当前线程是否被打断,判断完后会清除打断标记 |
isInterrupted() | 判断是否被打断,判断完后不会清除打断标记 |
currentThread() | 获取当前正在执行的线程 |
sleep(long n) | 休眠n毫秒 |
yield() | 提示线程调度器让出当前线程对CPU的使用 |
二、start与run
直接调用run()方法不使用start()方法不会启动新线程执行工作,全由main线程完成
@Slf4j(topic = "c.Test1")
public class Test1 {
public static void main(String[] args) {
Thread thread = new Thread("thread1") {
@Override
public void run() {
log.debug("xxx");
}
};
// 不会启动新线程
thread.run();
log.debug("kkk");
}
}
三、sleep与yield
- sleep
- 调用sleep会让线程从Running进入Timed Waiting(阻塞)状态
- 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
- 睡眠结束后的线程未必会立刻得到执行
- 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性
- yield
- 调用 yield 会让当前线程从 Running 进入 Runnable(就绪)状态,然后调度执行其它线程
- 具体的实现依赖于操作系统的任务调度器
四、join
@Slf4j(topic = "c.Test1")
public class Test1 {
private static int a = 0;
public static void main(String[] args) throws InterruptedException {
log.debug("开始");
Thread thread = new Thread(() -> {
log.debug("开始");
try {
Thread.sleep(10);
a = 10;
log.debug("结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread1");
thread.start();
// 等待结束,完成赋值操作
thread.join();
log.debug("a={}",a);
log.debug("结束");
}
}
五、interrupt
分两种情况
-
情况一:打断阻塞状态的线程sleep,wait,join。isInterrupted为false
@Slf4j(topic = "c.Test1") public class Test1 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { log.debug("开始"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } }, "thread1"); thread.start(); Thread.sleep(2000); // 打断 thread.interrupt(); // false log.debug("{}",thread.isInterrupted()); } }
-
情况二:打断正常状态线程,idInterrupted为true。当mian线程调用打断命令时,thread1线程仍会继续运行,需要在thread1内部退出线程。
@Slf4j(topic = "c.Test1") public class Test1 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { while (true){ // 获取当前线程的打断标记状态 boolean interrupted = Thread.currentThread().isInterrupted(); if (interrupted){ log.debug("打断了"); break; } } }, "thread1"); thread.start(); Thread.sleep(1000); // 打断 thread.interrupt(); // true log.debug("{}",thread.isInterrupted()); } }
-
两阶段终止模式
@Slf4j(topic = "c.Test1") public class Test1 { public static void main(String[] args) throws InterruptedException { TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination(); twoPhaseTermination.run(); Thread.sleep(2000); twoPhaseTermination.stop(); } } @Slf4j(topic = "c.Test1") class TwoPhaseTermination{ private Thread thread; public void run(){ thread = new Thread(() -> { // 当前线程 Thread current = Thread.currentThread(); while (true){ if (current.isInterrupted()) { log.debug("料理后事..."); break; } try { // 情况一 Thread.sleep(500); // 情况二 log.debug("执行监控"); } catch (InterruptedException e) { e.printStackTrace(); // 由于情况一会将打断标记设置为false,所以需要重新设置打断标记 current.interrupt(); } } }, "thread1"); thread.start(); } public void stop(){ // 打断操作 thread.interrupt(); } }
六、守护线程
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
@Slf4j(topic = "c.Test1")
public class Test1 {
public static void main(String[] args) throws InterruptedException {
log.debug("开始运行...");
Thread t1 = new Thread(() -> {
log.debug("开始运行...");
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("运行结束...");
}, "daemon");
// 设置该线程为守护线程
t1.setDaemon(true);
t1.start();
Thread.sleep(1);
log.debug("运行结束...");
}
}