1.守护线程和用户线程区别
JVM会等待非守护线程完成后关闭, 但不会等待守护线程
2.线程的生命周期
- 五个状态:新建,可运行(就绪),运行,阻塞,死亡
- 三种阻塞原因:sleep,wait,suspend
- 生命周期
以及
以及
3.如何结束一个一直运行的线程
场景一: 中断处于运行状态的线程
通常,我们通过“标记”方式终止处于“运行状态”的线程
- 中断标记
@Override
public void run() {
while (!isInterrupted()) {
// 执行任务...
}
}
说明:isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态,并且我们需要终止它时;可以调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环。注意:interrupt()并不会终止处于“运行状态”的线程!它会将线程的中断标记设为true。`
- 额外标记(自定义标记)
private volatile boolean flag= true;
@Override
public void run() {
while (flag) {
// 执行任务...
}
}
注意:将flag定义为volatile类型,是为了保证flag的可见性。即其它线程通过stopTask()修改了flag之后,本线程能看到修改后的flag的值。
场景二: 中断处于阻塞状态的线程
使用interrupt()
当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态;若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException异常。将InterruptedException放在适当的为止就能终止线程,形式如下:
@Override
public void run() {
try {
while (true) {
// 执行任务...
}
} catch (InterruptedException ie) {
// 由于产生InterruptedException异常,退出while(true)循环,线程终止!
}
}
参考 https://www.cnblogs.com/skywang12345/p/3479949.html
4.一个线程运行时发生异常会怎样
如果这个异常没有被捕获的话,这个线程就停止执行了。
另外重要的一点是:如果这个线程持有某个某个对象的监视器,那么这个对象监视器会被立即释放
5.创建线程的方式及实现
- 方式一,继承 Thread 类创建线程类。
- 方式二,通过 Runnable 接口创建线程类。
此方式可以使用线程池 - 方式三,通过 Callable 和 Future 创建线程。
此方式可以使用线程池
6.start 和 run 方法有什么区别
调用start()将创建新线程,run()将被执行;
直接调用run(),则不会创建线程,run()将作为普通方法执行
7.如何使用 wait + notify 实现通知机制
- wait和notify都属于Object类的,故所有类都可以调用这两个方法。
- 对象调用wait会阻塞当前线程,并释放对象锁
- 调用notify则不会释放对象锁,但是会随机唤醒一个线程,等当前线程继续执行完notify()之后,
synchronized
之内的代码。唤醒的线程则需要抢到锁才能执行。 - 其他通信机制:Condition,CountDownLatch,Queue,Future等
8.Thread类的 sleep 方法和对象的 wait 方法都可以让线程暂停执行,它们有什么区别
- sleep()是Thread的静态方法,调用sleep会让当前线程让出CPU给其他线程,但是并不释放持有的锁。休眠时间结束后当前线程进入就绪状态等待CPU时间片。
- wait()是Object的方法,调用对象的wait()会让当前线程释放对象的锁,当前线程将进入对象等待池,只有调用对象的
notify()
或notifyAll()
,才能唤醒等待线程,如果线程再次获取了锁就可以进入就绪状态。
为什么你应该在循环中检查等待条件
https://blog.csdn.net/qq_35181209/article/details/77362297
sleep、join、yield 方法有什么区别
- sleep让出当前线程CPU并进入休眠,让其他线程有机会继续执行,但当前线程并不释放对象锁
- yield和 sleep 方法类似,也不会释放“锁标志”。区别在于它没有参数,不能设置休眠时间,所以休眠线程可能又马上能进入执行状态。同时yield只会让出CPU给同优先级或高优先级线程。在实际场景下很少用yield.
- 让一个线程 B “加入”到另外一个线程 A 的尾部
sleep(0) 有什么用途
线程暂时放弃 CPU
你如何确保 main 方法所在的线程是 Java 程序最后结束的线程
使用 Thread 类的 #join() 方法
interrupt ,interrupted 和 isInterrupted 方法的区别
- interrupt:调用该方法的线程的状态为将被置为”中断”状态
- interrupted: 查询当前线程的中断状态,会清除状态
- isInterrupted:查询当前线程的中断状态,不会清除状态
Servlet 是线程安全吗
Servlet 是单实例多线程的,不安全
单例模式的线程安全性
单例模式的线程安全是指:某个单例类的实例在多线程环境下只会被创建一个。
- 饿汉式单例模式的写法:线程安全
public class Singleton {
private static final Singleton INSTANCE=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
优点:类加载即创建单例,整个过程不会有第二个对象,单例线程安全。
缺点:过早创建,影响性能。
- 懒汉式单例模式的写法:非线程安全
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton newInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}
优点:需要时才创建
缺点:多线程环境会创建多个对象
改造:
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
说明:可以保存单例多线程安全,但是synchronized
方法效率低
- 双检锁(DCL)单例模式的写法:线程安全
public class Singleton {
private static Singleton instance;
//private Volatitle static Singleton instance;
/*兼容JDK1.5的bug:对于instance = new Singleton(),JVM执行指令不确定,导致其他线程取到的instance可能还未初始化*/
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
单例模式参考 https://www.jianshu.com/p/12d1a151982e