前言
在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!”
博客主页:KC老衲爱尼姑的博客主页
博主的github,平常所写代码皆在于此
共勉:talk is cheap, show me the code
作者是爪哇岛的新手,水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
线程状态好比一个人的生命周期,从出生到死亡,期间会经历从婴儿到少年,从少年到青年,最终走向死亡。在java.lang.Thread.State枚举类中定义了以下六种线程的状态来描述线程的生命周期。
线程状态转移图
举个栗子,某天张三和李四打算去银行取钱,但是他们还没有行动起来,就是NEW状态,当张三和李四开始窗口前排队取钱时,就进入了Runnable状态。此状态下,排队的人员不管有没有被工作人员接待都属于Runnable状态,这个状态下的线程都具备了被分配时间片的资格,就等待调度器的调度。当张三因为一些事情需要去忙,比如需要回家拿身份证,拿手机,在发呆想妹子,此时进入了BLOCKED,WAITNG,TIME_WAITING状态。当张三和李四已经取完钱了,为TERMINATED状态。
阻塞 和等待的区别:
示例代码
public class ThreadStateTransfer {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 10; i++) {
}
}, "李四");
System.out.println(t.getName() + ": " + t.getState());
t.start();
//使用 isAlive 方法判定线程的存活状态
while (t.isAlive()) {
System.out.println(t.getName() + ": " + t.getState());
}
System.out.println(t.getName() + ": " + t.getState());
}
}
运行结果:
使用 jconsole 可以看到 t1 的状态是 TIMED_WAITING , t2 的状态是 BLOCKED
import java.util.concurrent.TimeUnit;
public class Demo3 {
private final static Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"t1");
t1.start();
Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println("hehehe");
}
},"t2");
t2.start();
}
}
运行结果:
t2正常的运行打印出hehehe,t1通过 jconsole 得知进去了等待状态
当银行张三进入了工作状态,他就会按照行动指南上的步骤去操作,直接完成工作为止,才结束。但是有时候会出现特殊情况,当张三给李四准备转钱的时候,老板突然给张三打来电话,说李四就是个骗子,需要立即停止转账,那老板如何通知张三停止转账呢?这就涉及了到对线程的停止方式。
示例代码
public class ThreadDemo {
private static class MyRunnable implements Runnable {
public volatile boolean isQuit = false;
@Override
public void run() {
while (!isQuit) {
System.out.println(Thread.currentThread().getName()
+ ": 别管我,我忙着转账呢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()
+ ": 啊!险些误了大事");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
System.out.println(Thread.currentThread().getName()
+ ": 让李四开始转账。");
thread.start();
Thread.sleep(10 * 1000);
System.out.println(Thread.currentThread().getName() + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
target.isQuit = true;
}
}
运行结果:
main: 让李四开始转账。
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
main: 老板来电话了,得赶紧通知李四对方是个骗子!
李四: 啊!险些误了大事Process finished with exit code 0
Thread中中断方法介绍
方法 | 说明 |
---|---|
public void interrupt() | 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位true |
public static boolean interrupted() | 判断当前线程的中断标志位是否设置,调用后清除标志位,改为false |
public boolean isInterrupted() | 判断对象关联的线程的标志位是否设置,调用后不清除标志位 |
示例代码
public class ThreadDemo3 {
private static class MyRunnable implements Runnable {
@Override
public void run() {
//Thread.currentThread()获得当前线程的引用
//这两种都可以获取中断状态
//while (!Thread.currentThread().isInterrupted()) {//检查线程的中断标记位,true-中断状态, false-非中断状态
while (!Thread.interrupted()) {//静态方法,返回当前线程的中断标记位,同时清除中断标记,改为false。比如当前线程已中断,调用interrupted(),返回true, 同时将当前线程的中断标记位改为false, 再次调用interrupted(),会发现返回false
System.out.println(Thread.currentThread().getName()
+ ": 别管我,我忙着转账呢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()
+ ": 有内鬼,终止交易!");
// 注意此处的 break
break;
//Thread.currentThread().interrupt();//设置中断位为true
}
}
System.out.println(Thread.currentThread().getName()
+ ": 啊!险些误了大事");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
System.out.println(Thread.currentThread().getName()
+ ": 让李四开始转账。");
thread.start();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
thread.interrupt();
}
}
运行结果:
main: 让李四开始转账。
李四: 别管我,我忙着转账呢!
李四: 别管我,我忙着转账呢!
main: 老板来电话了,得赶紧通知李四对方是个骗子!
李四: 有内鬼,终止交易!
李四: 啊!险些误了大事
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at org.example.thread.bit.ThreadDemo3$MyRunnable.run(ThreadDemo3.java:13)
at java.lang.Thread.run(Thread.java:748)Process finished with exit code 0
除了直接break退出循环,还可以通过重新设置标记位来退出,因为在触发InterruptedException异常的同时,JVM会同时把执行线程的中断标志位清除,此时调用执行线程的isInterrupted()或者interrupted(),会返回false。此时,正确的处理方式是在执行线程的run()方法中捕获到InterruptedException异常,并重新设置中断标志位。
示例代码
public class ThreadDemo4 {
private static class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.interrupted());//
}
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
thread.start();
thread.interrupt();//设置标记为true
}
}
运行结果:
true
false
false
false
false
false
false
false
false
falseProcess finished with exit code 0
示例代码
public class ThreadDemo4 {
private static class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread thread = new Thread(target, "李四");
thread.start();
thread.interrupt();
}
}
运行结果:
true
true
true
true
true
true
true
true
true
true