共计 4200 个字符,预计需要花费 11 分钟才能阅读完成。
举荐浏览
- 学习笔记《深刻了解 Java 虚拟机》
- 学习笔记《后端架构设计》
- 学习笔记《Java 基础知识进阶》
- 学习笔记《Nginx 学习笔记》
- 学习笔记《前端开发杂记》
- 学习笔记《设计模式学习笔记》
- 学习笔记《DevOps 最佳实际指南》
- 学习笔记《Netty 入门与实战》
- 学习笔记《高性能 MYSQL》
- 学习笔记《JavaEE 罕用框架》
- 学习笔记《Java 并发编程学习笔记》
- 学习笔记《分布式系统》
- 学习笔记《数据结构与算法》
1、线程的创立
在文章 线程的创立 & 线程优先级 文章中,咱们曾经理解了线程的创立过程,在运行线程之前,首先须要构建一个线程对象,线程对象须要一些线程的属性:所属线程组,线程优先级,以及是否是守护线程等等。
在创立线程对象实现之后,调用 start() 办法就能够启动这个线程。其语句为: 以后零碎同步告诉 JVM,只有线程布局器闲暇,应就立刻启动 start()办法所在的线程。
在线程创立的时候,最好为此线程设置线程名称,这样在前期排查或者 debug 的时候都十分不便,否则线程名称就是 Thread-X 的模式,十分的不直观。
2、线程的中断
中断是操作系统的概念,示意进行以后线程的执行,转而去执行中断函数,待中断函数执行实现之后,在继续执行线程的代码。在 Java 的设计中,中断则被用来标识一种线程的属性,用来标识线程是够被中断,通过应用办法 isInterrupted()
或者 Thread.currentTheard().isInterrupted()
查看线程是够被中断,咱们能够对线程进行特定的业务解决。
从 Java 的 API 中能够看到,许多申明抛出 InterruptedException 的办法(比方 Thread.sleep(long))在抛出异样之前,都会将以后线程的终端标记为设置为 false,而后在抛出 InterruptedException 异样,应用 isInterrupt 而 Exception 办法获取始终是 false。
当线程处于低等级期待状态,如果呈现中断请求,则会抛出 InterruptedException 异样,否则只将中断标记位设置为 true。
public class InterceptionMain {public static void main(String[] args) {SleepThread sleepThread = new SleepThread();
sleepThread.setDaemon(true);
BusyThread busyThread = new BusyThread();
busyThread.setDaemon(true);
sleepThread.start();
busyThread.start();
// 让两个线程都执行一段时间
SleepUtils.sleep(2);
sleepThread.interrupt();
busyThread.interrupt();
System.out.println("SleepThread Interrupted =" + sleepThread.isInterrupted());
System.out.println("BusyThread Interrupted =" + busyThread.isInterrupted());
SleepUtils.sleep(1);
}
}
// 繁忙的线程
public class BusyThread extends Thread {public BusyThread() {setName("BusyThread");
}
@Override
public void run() {while (true) {}}
}
// 闲暇休眠线程
public class SleepThread extends Thread {public SleepThread() {this.setName("Sleep Thread");
}
@Override
public void run() {SleepUtils.sleep(10000);
}
}
依据上文的剖析,输入后果如下,能够看到 SleepThread 线程抛出了 InterruptedException 异样,并且标记位被重置为 false
SleepThread Interrupted = false
BusyThread Interrupted = true
Exception in thread "Sleep Thread" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted
at com.company.utils.SleepUtils.sleep(SleepUtils.java:13)
at com.company.intercept.SleepThread.run(SleepThread.java:16)
3、暂停、复原与进行
实际上,Java 对于线程提供了看似好用的 API,用来暂停,复原以及进行线程,他们用起来十分的简略,不便。然而它们是被标记为作废,过期,它们存在一些性能和安全性问题。
首先看上面的程序
public class ThreadOperator {static SimpleDateFormat dataFormat = new SimpleDateFormat("HH:mm:ss");
public static void main(String[] args) {PrinterThread thread = new PrinterThread();
thread.start();
SleepUtils.sleep(3);
thread.suspend();
System.out.println("线程暂停于:" + dataFormat.format(new Date()));
SleepUtils.sleep(2);
thread.resume();
System.out.println("线程复原于:" + dataFormat.format(new Date()));
SleepUtils.sleep(4);
thread.stop();
System.out.println("线程进行于:" + dataFormat.format(new Date()));
}
static class PrinterThread extends Thread {SimpleDateFormat dataFormat = new SimpleDateFormat("HH:mm:ss");
@Override
public void run() {while (true) {System.out.println(dataFormat.format(new Date()));
SleepUtils.sleep(1);
}
}
}
}
// 输入后果
12:12:45
12:12:46
12:12:47
线程暂停于:12:12:48
线程复原于:12:12:50
12:12:50
12:12:51
12:12:52
12:12:53
线程进行于:12:12:54
- resume() 办法是具备死锁偏向的,在 JavaDoc 中官放的解释如下:
This method has been deprecated, as it is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed.
_
If the thread that would resume the target thread attempts to lock this monitor prior to callingresume
, deadlock results. Such deadlocks typically manifest themselves as “frozen” processes
_
这个办法是被废除的,因为其具备死锁的偏向。如果在调用某个线程 A 被暂停的时候,恰好这个线程 A 持有某个资源的锁,那么直到这个线程 A 被复原,否则没有任何线程可能拜访到这个锁的资源,也就是说_suspend()办法并不会开释持有的锁。_如果调用 A 的_resume()办法的线程 B,在调用之前想获取 A 线程持有的锁,此时 B 期待 A 开释锁,而 A 要想开释锁,就必须 B 执行 resume() 办法,就会进去典型的死锁状态。_
- stop() 办法具备不安全性,调用 stop() 办法并不会开释他所持有的锁,stop 办法比拟粗犷,并不会留工夫给线程解决其余的资源,比方开释锁,敞开文件等
4、优雅的敞开线程
除了应用线程终端来实现进行线程之外,咱们还能够通过设置标记位的形式来实现优雅的进行线程,须要次要的是,设置的标记位如果是全局变量的话应该 volatile 进行润饰。
public class CloseThread extends Thread {
private boolean on = true;
private int count = 0;
@Override
public void run() {while (on && !isInterrupted()) {count++;}
System.out.println("count =" + count);
System.out.println("程序执行实现");
}
public void onCancel() {this.on = false;}
public static void main(String[] args) {CloseThread closeThread = new CloseThread();
closeThread.start();
// 让线程执行一段时间
SleepUtils.sleep(1);
// 尝试敞开线程
closeThread.onCancel();
// 期待敞开实现
SleepUtils.sleep(1);
System.out.println("线程状态:" + closeThread.getState());
}
}
// 输入后果
count = 665265737
程序执行实现
线程状态:TERMINATED
5、参考资料
- 解决 InterruptedException 更加优化的解决 InterceptedException