Java Thread 线程
Thread 常用方法
join()
等待线程结束
void interrupt()
中断线程。如果当前线程正在运行,则只是设置中断标记,不会中断;如果当前线程处于非运行状态,则会抛出 InterruptedException 异常。
boolean isInterrupted()
获取线程中断状态。
public boolean isInterrupted() {
return isInterrupted(false);
}
boolean interrupted()
获取线程中断状态。如果当前已被中断,清除中断标记。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
其中 isInterrupted 含参数的方法定义如下
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
线程上下文
线程上下文切换的时机:当前线程 CPU 时间片使用完毕,或当前线程被其他线程中断。
死锁
死锁的四个条件
- 互斥。即线程持有的资源是排他的,不是共享的。
- 请求并持有。一个线程持有资源 A,但是请求资源 B,但是资源 B 被其他线程占用,因此这个线程阻塞,但是它也不释放资源 A。
- 不可剥夺。一个线程获取到的资源不会被别的线程强行抢走。
- 环路等待。必然存在一个环形的资源等待链。R1->R2->...->Rn->R1。
死锁代码:
public class DeadLock {
private static Object resourceA=new Object();
private static Object resourceB=new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resourceA) {
System.out.println(Thread.currentThread() + "get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "wait to get resourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get resourceB");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get resourceB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "wait to get resourceA");
synchronized (resourceA) {
System.out.println(Thread.currentThread() + "get resourceA");
}
}
});
thread1.start();
thread2.start();
}
}
Thread[Thread-0,5,main]get resourceA
Thread[Thread-1,5,main]get resourceB
Thread[Thread-0,5,main]wait to get resourceB
Thread[Thread-1,5,main]wait to get resourceA
线程 1 持有 resourceA,并请求 resourceB;线程 2 持有 resourceB,并请求 resourceA。造成了死锁。
避免死锁:将线程 2 获取资源的顺序改为和线程 1 获取资源的顺序保持一致。
Thread thread2 = new Thread(() -> {
synchronized (resourceA) {
System.out.println(Thread.currentThread() + "get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "wait to get resourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread() + "get resourceB");
}
}
});
Thread[Thread-0,5,main]wait to get resourceB
Thread[Thread-0,5,main]get resourceB
Thread[Thread-1,5,main]get resourceA
Thread[Thread-1,5,main]wait to get resourceB
Thread[Thread-1,5,main]get resourceB
由于资源的有序分配,当线程 1 和线程 2 同时执行到 synchronized (resourceA)
时,只会有一个线程拿到资源 A,假设线程 1 拿到,那么线程 2 会因为抢不到资源 A 而被阻塞。
于是,线程 1 能够顺利继续获取资源 B,使用完之后,释放资源 A 和资源 B。线程 2 接着重复线程 1 的操作。
守护线程与用户线程
线程可以使用 setDaemon(true) 方法设置为守护进程。
子线程的生命周期不受父线程影响。
当最后一个非守护线程结束时,JVM 会正常退出。只要有一个用户线程没结束,JVM 不会退出。
总结:非守护线程不会影响 JVM 的退出逻辑。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: ThreadLocal 线程本地变量
下一篇: 谈谈自己对于 AOP 的了解
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论